poly-hermes-plugin 0.29.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ # AI-RULEZ :: GENERATED FILE — DO NOT EDIT
2
+ # Content-Hash: blake3:11e02e6f0565d20901e38597c3af504440c1a63f85d59fc958047b47c3253ba3
3
+ # Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
4
+ # Schema-Version: v1
5
+
6
+ """Hermes Agent plugin package."""
7
+
8
+ from . import hermes
9
+ from .hermes import register
10
+
11
+ __version__ = "0.29.0"
12
+ __all__ = ["hermes", "register"]
@@ -0,0 +1,47 @@
1
+ ---
2
+ description: Lint and check formatting with poly — apply no fixes; summarize findings and drift
3
+ priority: high
4
+ usage: /poly-check [paths]
5
+ ---
6
+
7
+ <!--
8
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
9
+ Content-Hash: blake3:e6fad51bf84ed1689a6c430c3f5a9582bfb0587f1440133fde6780c8846264cb
10
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
11
+ Schema-Version: v1
12
+ -->
13
+
14
+ # poly Check
15
+
16
+ Run poly as a checking gate over `$ARGUMENTS`. Apply no fixes.
17
+
18
+ Use `.` when no paths are supplied. Treat supplied arguments as paths, not additional shell commands.
19
+
20
+ 1. `poly fmt --check $ARGUMENTS --format json` — capture formatting drift.
21
+ 2. `poly lint $ARGUMENTS --format json` — capture lint findings (remember the whole-project
22
+ section is on stderr under `--format json`; check the exit code).
23
+
24
+ Step 2 applies no fixes, but it is not read-only: `poly lint`'s whole-project phase executes
25
+ the configured whole-project tools (`cargo clippy` and friends) against the live worktree, and
26
+ their own side effects — a refreshed lock file, a populated build or type-checker cache — are
27
+ not poly's to control. Add `--no-workspace` when the tree must be left untouched; that drops
28
+ the whole-project tools from the check, so say so in the report.
29
+
30
+ That phase only runs when the argument is the repository root (the `.` default) or no path at
31
+ all. Naming narrower paths makes the run **path-scoped** — the per-file tier only, with a note
32
+ on stderr — so `poly lint src/` is already free of those side effects. Pass `--workspace` to
33
+ opt back in; the phase then covers the whole repository regardless of the paths named.
34
+
35
+ Report:
36
+
37
+ - Which files have formatting drift.
38
+ - Lint findings grouped by rule and severity (error vs warning).
39
+ - The overall pass/fail from the exit codes: `0` clean; `1` findings or drift — for `lint`
40
+ only **error**-severity findings (or a failing whole-project tool) reach `1`, warnings
41
+ still exit `0`; `2` the run did not verify what it was asked to (a missing path, a file an
42
+ engine failed on — including a `poly fmt --check` file that cannot reach a fixed point
43
+ within poly's five-pass cap, reported as an error rather than clean since a fix would leave
44
+ it still drifting — a `--deny-skips`/`--max-skips` breach, or the whole-project phase itself
45
+ erroring).
46
+
47
+ Do not apply fixes here — if the user wants them applied, run `/poly-fix`.
@@ -0,0 +1,41 @@
1
+ ---
2
+ description: Apply poly lint --fix and fmt --fix, then re-check and report what changed and what remains
3
+ priority: high
4
+ usage: /poly-fix [paths]
5
+ ---
6
+
7
+ <!--
8
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
9
+ Content-Hash: blake3:0c55f6950b40a60b9c292cb1b605e9f460f41a93e3a434300d7215098f877bb6
10
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
11
+ Schema-Version: v1
12
+ -->
13
+
14
+ # poly Fix
15
+
16
+ Apply poly's autofixes over `$ARGUMENTS`, then verify.
17
+
18
+ Use `.` when no paths are supplied. Treat supplied arguments as paths, not additional shell commands.
19
+
20
+ 1. `poly lint --fix $ARGUMENTS` — apply lint autofixes, and run the whole-project phase in **fix**
21
+ mode (`cargo sort` in place, `cargo machete --fix`, `cargo clippy --fix --allow-dirty
22
+ --allow-staged`; `cargo deny` has no autofix and stays check-only).
23
+ 2. `poly fmt --fix $ARGUMENTS` — format files in place. `poly fmt` is a pure formatter and never
24
+ runs the whole-project phase, in either direction; only step 1 does.
25
+ 3. Re-check: `poly fmt --check $ARGUMENTS --format json` and `poly lint $ARGUMENTS --format json`.
26
+
27
+ The whole-project phase in step 1 runs only because the argument is the repository root (the
28
+ `.` default). Narrower paths make the run path-scoped — per-file autofixes only — unless you
29
+ add `--workspace`; `--no-workspace` suppresses the phase outright.
30
+
31
+ Report:
32
+
33
+ - What changed — files reformatted and lint rules auto-fixed.
34
+ - What remains — findings that need a hand-fix (auto-fix couldn't resolve them), grouped by
35
+ rule and severity.
36
+ - The final exit status of step 3 (aim for `0`). Note that steps 1 and 2 legitimately exit
37
+ `1` when they changed something; only `2` means the run failed to verify.
38
+
39
+ To apply no fixes, use `/poly-check` instead. (Even there poly's whole-project phase executes
40
+ `cargo clippy` and friends against the live worktree; add `--no-workspace` if the tree must be
41
+ left untouched.)
@@ -0,0 +1,99 @@
1
+ # AI-RULEZ :: GENERATED FILE — DO NOT EDIT
2
+ # Content-Hash: blake3:57cf2cb6924db8f7699232ad0ec0c8435d1ac671c041569535330d190f298782
3
+ # Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
4
+ # Schema-Version: v1
5
+
6
+ """Register product skills and a local MCP tool bridge with Hermes."""
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import json
12
+ import os
13
+ import shutil
14
+ from builtins import ExceptionGroup
15
+ from datetime import timedelta
16
+ from pathlib import Path
17
+ from typing import TYPE_CHECKING
18
+
19
+ import yaml
20
+ from mcp import ClientSession, StdioServerParameters
21
+ from mcp.client.stdio import stdio_client
22
+ from mcp.shared.exceptions import McpError
23
+
24
+ if TYPE_CHECKING:
25
+ from hermes_cli.plugins import PluginContext
26
+
27
+ PLUGIN_NAME = "poly"
28
+ CLI_COMMAND = "poly"
29
+ SERVER_ARGUMENTS = ["mcp"]
30
+ TOOL_NAMES = ['cache_clean', 'cache_stats', 'config_show', 'format_check', 'format_write', 'lint', 'lint_fix', 'rules', 'version', 'workspace_lint', 'workspace_lint_fix']
31
+ DISCOVERY_TOOL = "list_tools"
32
+ REQUEST_TIMEOUT_SECONDS = 300
33
+
34
+
35
+ def error_details(error: BaseException) -> str:
36
+ """Expose SDK task-group causes instead of hiding the actionable failure."""
37
+ if isinstance(error, ExceptionGroup):
38
+ return "; ".join(error_details(cause) for cause in error.exceptions)[:1024]
39
+ return str(error)[:1024]
40
+
41
+
42
+ async def call_tool(arguments: dict[str, object], **_kwargs: object) -> dict[str, object]:
43
+ """Call one supported MCP tool using the installed local CLI."""
44
+ if not isinstance(arguments, dict) or set(arguments) - {"tool", "tool_arguments"}:
45
+ return {"error": "Pass an object containing tool and optional tool_arguments."}
46
+ tool = arguments.get("tool")
47
+ parameters = arguments.get("tool_arguments", {})
48
+ if tool not in [*TOOL_NAMES, DISCOVERY_TOOL] or not isinstance(parameters, dict):
49
+ return {"error": "Choose a supported tool and provide an object of tool_arguments."}
50
+ command = shutil.which(CLI_COMMAND)
51
+ if command is None:
52
+ return {"error": f"Install {CLI_COMMAND} with MCP support and put it on PATH; see the plugin README."}
53
+
54
+ server = StdioServerParameters(command=command, args=SERVER_ARGUMENTS, env=os.environ.copy())
55
+ try:
56
+ async with asyncio.timeout(REQUEST_TIMEOUT_SECONDS):
57
+ async with (
58
+ stdio_client(server) as (read, write),
59
+ ClientSession(read, write, read_timeout_seconds=timedelta(seconds=REQUEST_TIMEOUT_SECONDS)) as session,
60
+ ):
61
+ await session.initialize()
62
+ if tool == DISCOVERY_TOOL:
63
+ result = await session.list_tools()
64
+ else:
65
+ result = await session.call_tool(tool, parameters)
66
+ return result.model_dump(mode="json", exclude_none=True)
67
+ except TimeoutError:
68
+ return {"error": f"{CLI_COMMAND} MCP request timed out; reduce the workload or inspect server diagnostics."}
69
+ except (McpError, OSError, ExceptionGroup, ValueError) as error:
70
+ return {"error": f"{CLI_COMMAND} MCP request failed: {error_details(error)}"}
71
+
72
+
73
+ async def handle_tool(arguments: dict[str, object], **kwargs: object) -> str:
74
+ """Return the native text contract while preserving structured MCP fields as JSON."""
75
+ return json.dumps(await call_tool(arguments, **kwargs), ensure_ascii=False)
76
+
77
+
78
+ def register(ctx: PluginContext) -> None:
79
+ """Register every bundled skill and one tool spanning the native MCP surface."""
80
+ for path in sorted((Path(__file__).parent / "skills").glob("*/SKILL.md")):
81
+ frontmatter = path.read_text(encoding="utf-8").split("---", 2)[1]
82
+ metadata = yaml.safe_load(frontmatter)
83
+ ctx.register_skill(metadata["name"], path, description=metadata["description"])
84
+ name = PLUGIN_NAME.replace("-", "_") + "_call"
85
+ description = f"Call a {PLUGIN_NAME} tool on the installed local MCP server. Select list_tools to inspect request schemas; use namespaced skills for workflows."
86
+ schema = {
87
+ "name": name,
88
+ "description": description,
89
+ "parameters": {
90
+ "type": "object",
91
+ "properties": {
92
+ "tool": {"type": "string", "enum": [*TOOL_NAMES, DISCOVERY_TOOL]},
93
+ "tool_arguments": {"type": "object", "description": "Arguments accepted by the selected MCP tool."},
94
+ },
95
+ "required": ["tool"],
96
+ "additionalProperties": False,
97
+ },
98
+ }
99
+ ctx.register_tool(name=name, toolset=PLUGIN_NAME, schema=schema, handler=handle_tool, is_async=True)
@@ -0,0 +1,8 @@
1
+ name: "poly"
2
+ version: "0.29.0"
3
+ description: "Zero-dependency lint & format orchestrator over MCP — one pure-Rust binary wrapping ruff/oxc/taplo/rumdl and more as in-process backends, plus a tree-sitter generic tier for everything else. Exposes lint/format/cache tools with structured JSON output."
4
+ author: "Na'aman Hirschfeld"
5
+ kind: "standalone"
6
+ python_dependencies:
7
+ - "mcp==1.28.1"
8
+ - "PyYAML==6.0.3"
@@ -0,0 +1,110 @@
1
+ ---
2
+ description: Running poly lint / poly fmt — --fix, --format pretty|json|toon, --exclude, --config, exit codes, inline suppression, and the check → read-json → fix → re-check loop
3
+ name: poly-lint-and-format
4
+ license: MIT
5
+ metadata:
6
+ author: Goldziher
7
+ repository: https://github.com/Goldziher/poly
8
+ ---
9
+
10
+ <!--
11
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
12
+ Content-Hash: blake3:697a8913634eec72ba2340417d11f811af8d9fcd390f25ccdc09ed4689695209
13
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
14
+ Schema-Version: v1
15
+ -->
16
+
17
+ # poly Lint and Format
18
+
19
+ ## Commands
20
+
21
+ - `poly lint [PATHS]…` — run the linters. poly applies no fixes without `--fix`; `--fix`
22
+ applies autofixes (and the whole-project fix phase). `--no-workspace` restricts to the
23
+ per-file tier — and is also what makes a run read-only: without it, plain `poly lint`
24
+ still *executes* the configured whole-project tools against the live worktree, and their
25
+ own side effects (a refreshed lock file, a populated build or type-checker cache) are not
26
+ poly's to control. Naming paths that **narrow** the run skips that phase by default
27
+ (`poly lint .` names the repo root, so it does *not* narrow and the phase still runs);
28
+ `--workspace` opts back in, and the tools then cover the whole repository regardless of
29
+ the named paths and of `[discovery] exclude`.
30
+ - `poly fmt [PATHS]…` — **dry run by default**: reports what would change and writes
31
+ nothing. `--fix` writes changes; `--check` is the explicit form of the default dry run
32
+ and conflicts with `--fix`. `poly fmt` is a pure formatter — it never runs the
33
+ whole-project lint phase.
34
+
35
+ ## Flags
36
+
37
+ - `--format pretty|json|toon` — `pretty` (the default) is the colored, human-oriented
38
+ output; `json` and the compact `toon` variant are machine-readable. Under
39
+ `--format json`/`toon`, `poly lint`'s whole-project section and every note (discovery,
40
+ skips, errors) go to stderr so stdout stays a single valid document — a machine consumer
41
+ must check the **exit code**, not just the payload.
42
+ - `--exclude <glob>` — skip paths on top of `.gitignore` (repeatable; merged with
43
+ `[discovery] exclude`). Gitignore-style: a glob without a leading `/` matches a directory
44
+ of that name at **any** depth (`e2e/**` also prunes `src/test/java/io/xberg/e2e/`), while
45
+ a leading `/` anchors it to the config directory (`/e2e/**`). `poly doctor` warns when a
46
+ rule matches at more than one depth.
47
+ - `--include-excluded` — check explicitly named files or directory roots even when they
48
+ match the exclude set. Exclusions *below* an included directory stay active. Applying the
49
+ exclude set to explicitly named paths is already the default, so `--force-exclude` is
50
+ accepted only as a compatibility no-op — the flag is parsed and never read.
51
+ - `--config <path>` — point at a specific `poly.toml`.
52
+ - `--no-cache` — bypass the blake3 content-hash result cache.
53
+ - `-j <N>` — parallelism; `--no-color` — plain output; `--verbose` — extra per-finding
54
+ detail in `pretty` output; `--debug` — per-engine cache hit/miss and timing, plus
55
+ debug-level logs on stderr.
56
+ - `--fix-generated` — let `--fix` rewrite files marked `DO NOT EDIT` / `@generated`, which
57
+ it otherwise reports on but leaves alone.
58
+ - `--deny-skips` / `--max-skips <N>` — strict coverage. A **skipped** file is one nothing
59
+ inspected: a path named on the command line that no engine covers (`App.csproj`), or a
60
+ file every routed backend declined (Go-templated YAML, a hash-stamped generated file). A
61
+ skip the caller instructed — `--only`/`--skip` narrowing an engine out, or `enabled = false`
62
+ in config — is **not** charged against the budget, since it names itself in the report
63
+ rather than losing coverage silently; only a poly limitation counts. Skips are always
64
+ reported and named; these flags make a chargeable skip fail the run (exit `2`), naming
65
+ every file it fired on. `--verbose` lists every skip in `pretty` output; `--format
66
+ json`/`toon` carries the full set both as a top-level `skipped` array and as synthetic
67
+ `results` entries — `summary.skipped` is the authoritative count, so read it first and use
68
+ the set only to name the files.
69
+
70
+ ## Exit codes
71
+
72
+ - `0` — clean (no findings, no drift).
73
+ - `1` — error-severity findings, formatting drift, or a failing whole-project tool.
74
+ - `2` — an error (bad config, tool failure), or work the run could not verify: a missing
75
+ path argument, a file an engine failed on — including a `poly fmt` file that could not
76
+ reach a fixed point within its five-pass cap, now reported as an error rather than
77
+ silently claimed as formatted — or a `--deny-skips`/`--max-skips` breach.
78
+
79
+ `poly lint` exits non-zero only on **error-severity** findings; warnings do not fail CI —
80
+ which is why the on-by-default `quality` and built-in ast-grep rules (all warnings) never
81
+ turn a green pipeline red on their own.
82
+
83
+ ## Inline suppression
84
+
85
+ Silence one finding in place with a directive written in the host language's own comment
86
+ syntax:
87
+
88
+ ```rust
89
+ let value = map.get(key).unwrap(); // poly: allow[unwrap-used] key is validated above
90
+ ```
91
+
92
+ - `poly: allow[RULE] reason` — a comment-only line suppresses the next non-blank line; a
93
+ trailing comment suppresses its own line.
94
+ - `poly: allow-file[RULE] reason` — suppresses the whole file wherever it appears, and is
95
+ the only form that can suppress a diagnostic with no span.
96
+ - `[RULE]` accepts a comma-separated list, or `*` for every rule.
97
+ - **A reason is mandatory.** A directive whose text after `]` has no alphanumeric character
98
+ does **not** suppress, and reports `lazy-ignore` instead — an empty comment cannot buy a
99
+ bypass.
100
+ - Applied centrally in the runner, so it works for every engine (ruff, oxlint, quality,
101
+ ast-grep, …). For a whole file or a class of files, use `[per-file-ignores]` in
102
+ `poly.toml` instead.
103
+
104
+ ## The loop
105
+
106
+ 1. `poly fmt --check . --format json` and `poly lint . --format json` — capture drift and
107
+ findings, checking the exit code.
108
+ 2. Read the JSON to see exactly which files and rules are involved.
109
+ 3. `poly fmt --fix .` then `poly lint --fix .` to apply what is auto-fixable.
110
+ 4. Re-run the checks; hand-fix whatever remains (exit code back to 0).
@@ -0,0 +1,10 @@
1
+ <!--
2
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
3
+ Content-Hash: blake3:827e04e800b869af141ac06d2edd7bf69516c05790bdbf03210a4d802ea6f3b9
4
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
5
+ Schema-Version: v1
6
+ -->
7
+
8
+ # Concepts
9
+
10
+ * [Poly Lint And Format](SKILL.md) - Running poly lint / poly fmt — --fix, --format pretty|json|toon, --exclude, --config, exit codes, inline suppression, and the check → read-json → fix → re-check loop
@@ -0,0 +1,124 @@
1
+ ---
2
+ description: The poly MCP server — the eleven tools and which are read-only vs mutating, the paths/exclude/config/format params, async Tasks for the whole-project phase, and the isError contract
3
+ name: poly-mcp
4
+ license: MIT
5
+ metadata:
6
+ author: Goldziher
7
+ repository: https://github.com/Goldziher/poly
8
+ ---
9
+
10
+ <!--
11
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
12
+ Content-Hash: blake3:3e891f0be46a80c56b06b9a9683a91b16c293cdb33edb5aebefaa7c680be3b3c
13
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
14
+ Schema-Version: v1
15
+ -->
16
+
17
+ # poly MCP
18
+
19
+ `poly mcp` is a stdio MCP server exposing poly's lint/format/cache/rules/config surface as
20
+ tools. Prefer it over shelling out to the CLI when working through MCP — every tool returns
21
+ typed `structured_content` (with a declared output schema) plus one text block that mirrors
22
+ the CLI's `--format json`, or the compact TOON encoding when asked.
23
+
24
+ `poly mcp --config <PATH>` pins a fallback config file for requests that do not name one.
25
+
26
+ ## Tool surface
27
+
28
+ Eleven tools, no more. Read-only (never touch the tree):
29
+
30
+ - `lint` — run the linters and return diagnostics. Mirrors `poly lint`.
31
+ - `format_check` — report formatting drift without writing. Mirrors `poly fmt --check`.
32
+ - `cache_stats` — result-cache footprint (entries, bytes, format version) per namespace.
33
+ - `rules` — list every ast-grep rule a run would apply — poly's built-in pack plus the user
34
+ rules from `[rules] dirs` — and optionally run their `*-test.yml` snippets. Mirrors `poly
35
+ rules list` / `poly rules test`. Each rule carries its language, `source` (`builtin`/`user`),
36
+ `default_severity`, the `severity` it reports at under the resolved config, and `enabled`.
37
+ - `config_show` — the merged effective configuration. Mirrors `poly config show`, and is
38
+ **network-free**: remote `extends` bases are not fetched.
39
+ - `version` — which poly binary is serving this session (version, build id, channel,
40
+ executable, pid, uptime), the full compiled-in engine → wrapped-tool-version map, and
41
+ whether that executable is still the file on disk. It answers even when the binary has
42
+ moved, which is what makes it the tool that explains why the others stopped.
43
+
44
+ Mutating (write to the tree):
45
+
46
+ - `lint_fix` — apply lint autofixes. Mirrors `poly lint --fix`.
47
+ - `format_write` — format files in place. Mirrors `poly fmt --fix`.
48
+ - `cache_clean` — clear the result cache and report freed bytes.
49
+
50
+ Whole-project (long-running):
51
+
52
+ - `workspace_lint` — the whole-project phase in check mode: `cargo clippy` / `cargo-sort` /
53
+ `cargo-machete` / `cargo-deny` and configured inline whole-project jobs, over the whole
54
+ repository (it takes no `paths`).
55
+ - `workspace_lint_fix` — the same phase in fix mode; writes files.
56
+
57
+ Both are exposed as async Tasks (SEP-2663): the call returns a task handle and the client
58
+ polls `tasks/get`, optionally `tasks/cancel`, with an unlimited TTL. A client that does not
59
+ declare the tasks capability gets a synchronous, blocking result from the same call instead,
60
+ so the tools work either way.
61
+
62
+ `workspace_lint` applies no fixes, but it is **not** in the never-touch-the-tree group: it
63
+ executes those tools against the live worktree, and their own side effects — a refreshed
64
+ lock file, a populated build or type-checker cache — are not poly's to control.
65
+
66
+ There is no `hooks` tool: `poly hooks` is CLI-only.
67
+
68
+ ## Parameters
69
+
70
+ - `lint` / `format_check` / `lint_fix` / `format_write`: `paths` (files or directories;
71
+ empty means the current directory), `exclude` (gitignore-style globs merged with
72
+ `[discovery] exclude` — unanchored globs match at any depth), `config` (path to a
73
+ `poly.toml`), `format` (`"json"` default, or `"toon"`).
74
+ - `rules`: `dirs` (empty means `[rules] dirs` from the config), `config`, `test` (bool),
75
+ `format`.
76
+ - `config_show`: `config`, `format`.
77
+ - `cache_stats` / `cache_clean` / `version`: `format` only.
78
+ - `workspace_lint` / `workspace_lint_fix`: `config`, `format`, `jobs`, `no_cache` — no
79
+ `paths`.
80
+
81
+ `format` selects only the paired **text** block; `structured_content` is always JSON.
82
+
83
+ Treat the read-only tools as safe to call freely; gate the mutating tools behind explicit
84
+ intent since they change files.
85
+
86
+ ## Every result identifies the binary that answered
87
+
88
+ Each result carries a `poly` block (version, build id, channel, executable, pid, and an
89
+ `engines` digest — a blake3 hash over the sorted compiled-in engine name + version pairs,
90
+ excluding native-toolchain and catalog engines since those depend on the host and on config)
91
+ in `structured_content` and in `_meta`, because an MCP caller has no `poly --version` to fall
92
+ back on. The digest is what distinguishes two builds sharing one version number (a `dev`
93
+ build, or two builds of one tag) when their wrapped crates differ; the full engine map is on
94
+ the `version` tool. The server fingerprints its own executable at startup and re-checks it per
95
+ request: if the binary is replaced or deleted underneath a long-lived server, every tool but
96
+ `version` fails rather than answering with superseded behaviour.
97
+
98
+ ## Per-file outcomes: checked, skipped, error
99
+
100
+ The result object is `{results, errors, skipped, summary, configs}`, not a bare array.
101
+ `summary` is `{checked, skipped, errored}` — the run's own count of what it did, and the field
102
+ to gate on. It cannot be derived from `results`: `results` holds only files with something to
103
+ report, so a file that was checked and found clean produces **no** `results` entry at all — a
104
+ present entry does not mean checked, either, since `results` also carries a synthetic entry
105
+ (empty `diagnostics`, `skipped` or `error` set) for every file the run declined or failed on.
106
+ The skipped/error sets and `results` overlap on purpose:
107
+
108
+ - **Checked** — counted in `summary.checked`. Not derivable from `results`.
109
+ - **Skipped** (`skipped` field, and the top-level `skipped` array) — poly correctly declined the
110
+ file (e.g. a template dialect no backend handles). Not a failure.
111
+ - **Errored** (`error` field, and the top-level `errors` array) — poly failed to process the
112
+ file (unreadable file, backend crash, bad engine config). Distinct from `skipped` on purpose:
113
+ a skip is a deliberate decision, an error is poly failing on a file it accepted.
114
+
115
+ The top-level `errors` array duplicates the `error`-carrying records in `results` so a caller
116
+ can gate on "did the run fail on anything" without scanning every record. When `errors` is
117
+ non-empty, the tool result's `CallToolResult.is_error` (`isError` over the wire) is set `true`.
118
+
119
+ **An MCP-driving agent must check `isError` (or `summary.errored`) before trusting any other
120
+ part of the result.** Before this shape existed, a file poly failed to process was absent from
121
+ the output entirely — indistinguishable from a file that was checked and found clean. An agent
122
+ that gated on "no findings in `results`" was reading a run that had silently failed to check
123
+ some files as a clean pass. Check `isError` first; only then read `summary` for coverage and
124
+ `results` for diagnostics.
@@ -0,0 +1,10 @@
1
+ <!--
2
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
3
+ Content-Hash: blake3:041e6c4ec0de96e350e6b4a73ef9d19e5d4f73af9368e6ee0b61c54f7ce5957d
4
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
5
+ Schema-Version: v1
6
+ -->
7
+
8
+ # Concepts
9
+
10
+ * [Poly Mcp](SKILL.md) - The poly MCP server — the eleven tools and which are read-only vs mutating, the paths/exclude/config/format params, async Tasks for the whole-project phase, and the isError contract
@@ -0,0 +1,66 @@
1
+ ---
2
+ description: Use poly as the single lint/format gate instead of invoking ruff/oxlint/rustfmt directly — one poly.toml, poly hooks install, poly migrate, CI via the Goldziher/poly setup Action
3
+ name: poly-orchestrator
4
+ license: MIT
5
+ metadata:
6
+ author: Goldziher
7
+ repository: https://github.com/Goldziher/poly
8
+ ---
9
+
10
+ <!--
11
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
12
+ Content-Hash: blake3:3363494043f7c9784c37f40b9ed195ca372dc87bebd5f35072722e988c20773a
13
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
14
+ Schema-Version: v1
15
+ -->
16
+
17
+ # poly as the Orchestrator
18
+
19
+ Treat poly as the **single** lint and format gate for the repository. Do not invoke ruff,
20
+ oxlint, taplo, rumdl, or the rest directly — poly compiles them in as backends, and covers
21
+ everything else via the tree-sitter generic tier, the `quality` metric tier, and its built-in
22
+ ast-grep rule pack, behind one binary, one config, and one report.
23
+
24
+ ## Adopt it
25
+
26
+ - **One `poly.toml`.** Configure every language and rule in a single per-repo file
27
+ (`poly.local.toml` for local overrides, `extends` to share a base). Layering is
28
+ tool default → poly's opinionated overrides → your `poly.toml`. In a monorepo a nested
29
+ `poly.toml` deep-merges on top of its ancestors for the files beneath it.
30
+ - **`poly migrate`** — absorb existing tool configs into `poly.toml` instead of
31
+ hand-writing it. It imports **ruff, typos, taplo, and markdownlint** configs; there is no
32
+ eslint, prettier, or pre-commit importer. The default is a dry-run report — pass `--write`
33
+ to apply, `--recurse` for a monorepo, `--verify` to re-run poly afterwards, and
34
+ `--strip-superseded` to also remove `pyproject.toml` sections for tools ruff replaces.
35
+ - **`poly hooks install`** — wire the git-hook shims so `poly` runs the configured stages on
36
+ every commit, replacing a `.pre-commit-config.yaml`. It installs the hook types your
37
+ `poly.toml` configures; `--hook-type` picks specific ones and `--overwrite` discards a
38
+ preserved legacy hook. `poly hooks uninstall` restores what was there before.
39
+ - **`poly config show`** prints the effective merged config; **`poly config update`** pins a
40
+ symbolic remote `extends` ref into `poly-config.lock`.
41
+ - **`poly doctor`** reports which poly is running, every poly on PATH, and the config in
42
+ effect — the first thing to run when two machines disagree.
43
+
44
+ ## CI
45
+
46
+ `Goldziher/poly@v0` is a **setup** action: it installs the `poly` binary (with optional
47
+ caching) and puts it on `PATH`. It does not run poly for you — invoke the commands yourself
48
+ in following steps.
49
+
50
+ ```yaml
51
+ - uses: actions/checkout@v4
52
+ - uses: Goldziher/poly@v0 # inputs: version (default latest), cache, github-token
53
+ - run: poly fmt --check .
54
+ - run: poly lint .
55
+ ```
56
+
57
+ poly is one pinned binary with no *required* system dependencies, so local, hook, and CI
58
+ runs agree — with one caveat: the native-toolchain tier means `rustfmt` and `gofmt` are used
59
+ automatically whenever they are on `PATH`, and formatting output then depends on that tool's
60
+ version. A machine without them silently falls through to the lower-fidelity tree-sitter
61
+ tier. Pin the Rust/Go toolchain in CI (and expect drift otherwise), or set
62
+ `[fmt.rust.rustfmt] enabled = false` / `[fmt.go.gofmt] enabled = false` to stop the subprocess.
63
+ That does not leave the language unformatted: `rustfmt`/`gofmt` are the one pair of backends
64
+ that read `enabled` themselves and hand the file to the tier-2 reindenter when disabled, rather
65
+ than expecting the runner to drop them from the plan — so the file is still formatted, just at
66
+ lower fidelity than the native tool.
@@ -0,0 +1,10 @@
1
+ <!--
2
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
3
+ Content-Hash: blake3:a320c195ce6d97513905afe7995e590161abfcbd3ed11eff6d3afbeae48df185
4
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
5
+ Schema-Version: v1
6
+ -->
7
+
8
+ # Concepts
9
+
10
+ * [Poly Orchestrator](SKILL.md) - Use poly as the single lint/format gate instead of invoking ruff/oxlint/rustfmt directly — one poly.toml, poly hooks install, poly migrate, CI via the Goldziher/poly setup Action
@@ -0,0 +1,69 @@
1
+ ---
2
+ description: What poly is — the native, tree-sitter, native-toolchain, quality, and built-in-rule-pack tiers, language coverage, and when to reach for it
3
+ name: poly-overview
4
+ license: MIT
5
+ metadata:
6
+ author: Goldziher
7
+ repository: https://github.com/Goldziher/poly
8
+ ---
9
+
10
+ <!--
11
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
12
+ Content-Hash: blake3:273b80b1cc5f091780eac739023a29774686024091327f99c639532e042d2ff6
13
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
14
+ Schema-Version: v1
15
+ -->
16
+
17
+ # poly Overview
18
+
19
+ poly is a single pure-Rust binary that lints and formats a whole repository across
20
+ languages. It wraps best-in-class tools as in-process crate backends and falls back to a
21
+ tree-sitter generic tier for everything else, so it runs the same on any machine and in CI.
22
+ No system tool is ever *required*; the one scoped exception is the native-toolchain tier
23
+ below, which uses a language's canonical CLI when it happens to be installed.
24
+
25
+ ## Per-language coverage tiers
26
+
27
+ - **Tier 1 — native in-process backends.** Highest fidelity, compiled straight into the
28
+ binary and registered per language in `registry.rs`: `ruff` (Python), `oxc`
29
+ (JS/TS/JSX/TSX/JSON/JSONC), `taplo` (TOML), `rumdl` (Markdown/MDX), `sqruff` (SQL), YAML,
30
+ `malva` (CSS/SCSS/LESS) + `biome` (CSS/SCSS), `markup_fmt` (HTML/Vue/Svelte/Astro/Angular/Jinja/
31
+ Vento/Mustache/XML), `mago` (PHP), `rubyfmt` (Ruby), `graphql` + `biome` (GraphQL),
32
+ `nixfmt` (Nix), `hcl`, Dockerfile, dotenv, and INI.
33
+ - **Tier 2 — tree-sitter generic tier.** The catch-all for the long tail (Elixir, C/C++,
34
+ C#, protobuf, and the rest of 300+ grammars). CST-driven structural reindent for
35
+ brace-family grammars, whitespace normalization otherwise, and a `LEAVE_UNTOUCHED` list
36
+ for grammars where whitespace is significant. Best-effort, pure Rust, grammars loaded on
37
+ demand — never gofmt/rustfmt parity, by design.
38
+ - **Native-toolchain tier (scoped exception).** A language's canonical first-party CLI run
39
+ per file over stdin/stdout when installed: `rustfmt`, `gofmt` and `shellcheck` are **on by
40
+ default when found on PATH**; `zig fmt`, `shfmt`, `google-java-format`, `ktfmt`, `styler`
41
+ (R), `swift-format`, `dart format`, and `gleam format` are opt-in via
42
+ `[fmt.<lang>.<tool>] enabled = true` / `[lint.<lang>.<tool>] enabled = true`. When the
43
+ tool is absent, formatting falls through to tier 2 with an info-level notice, so the
44
+ zero-dependency guarantee always holds.
45
+
46
+ ## Cross-cutting engines (every language)
47
+
48
+ Four engines are appended to every language regardless of tier:
49
+
50
+ - **`typos`** — spelling in identifiers, comments, and strings.
51
+ - **`quality`** — structural code-quality metrics off the tree-sitter parse: file/function/
52
+ type length, nesting depth, cyclomatic complexity, parameter count, and `lazy-ignore`.
53
+ Warning severity, on by default. The structural rules need a verified node-kind table and
54
+ run for Python, Rust, Go, JavaScript, TypeScript, TSX, Java, Kotlin, C, C++, C#, and Ruby;
55
+ `magic-number` and `law-of-demeter` are opt-in. Configure under `[lint.quality]`.
56
+ - **`astgrep`** — ast-grep pattern rules. poly embeds a **built-in rule pack** of 26 rules
57
+ across 9 languages (C#, Elixir, Go, Java, Kotlin, Python, Ruby, Rust, Swift), on by
58
+ default; 13 of them ship `severity: off`. User rules under `[rules] dirs` (default
59
+ `.poly/rules`) layer on top and replace a pack rule sharing its `id`. Disable the pack
60
+ wholesale with `[rules] builtin = false`.
61
+ - **`uncomment`** — opt-in comment removal, off unless `[lint.uncomment] enabled = true`.
62
+
63
+ ## When to use it
64
+
65
+ Reach for poly as the single lint/format gate for any repo: local dev, git hooks, and CI.
66
+ It replaces invoking ruff / oxlint / rustfmt / prettier individually — one binary, one
67
+ `poly.toml`, one report. A language with no native backend still gets tier-2 formatting
68
+ plus the cross-cutting engines, so poly covers the whole tree rather than only the
69
+ languages you wired up by hand.
@@ -0,0 +1,10 @@
1
+ <!--
2
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
3
+ Content-Hash: blake3:948de85c38f4ceee5ac758d6b75670c18be2a3850757a17f1b0546d467019698
4
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
5
+ Schema-Version: v1
6
+ -->
7
+
8
+ # Concepts
9
+
10
+ * [Poly Overview](SKILL.md) - What poly is — the native, tree-sitter, native-toolchain, quality, and built-in-rule-pack tiers, language coverage, and when to reach for it
@@ -0,0 +1,129 @@
1
+ ---
2
+ description: poly's coverage tiers (native / tree-sitter / native-toolchain / quality / built-in ast-grep pack), the per-file tier vs the whole-project phase (--no-workspace), staged isolation (ADR 0019), and hierarchical poly.toml in monorepos (ADR 0018)
3
+ name: poly-tiers-and-scope
4
+ license: MIT
5
+ metadata:
6
+ author: Goldziher
7
+ repository: https://github.com/Goldziher/poly
8
+ ---
9
+
10
+ <!--
11
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
12
+ Content-Hash: blake3:ad140ec77b0aed2a08b9c7261e16d5f9cde428c88e6e249a9891a24e6f35b964
13
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
14
+ Schema-Version: v1
15
+ -->
16
+
17
+ # poly Tiers and Scope
18
+
19
+ ## Coverage tiers inside the per-file pass
20
+
21
+ Five mechanisms decide what actually inspects a file (`crates/poly-core/src/registry.rs`):
22
+
23
+ 1. **Tier-1 native crate backends** — one in-process Rust crate registered for specific
24
+ languages: ruff, oxc, taplo, rumdl, sqruff, yaml, malva (+ biome for CSS/SCSS), markup_fmt, mago, rubyfmt,
25
+ graphql, nixfmt, hcl, dockerfile, dotenv, ini.
26
+ 2. **Tier-2 tree-sitter generic tier** (ADR 0004) — the catch-all for every language with no
27
+ native backend. Structural reindent for brace-family grammars, whitespace normalization
28
+ otherwise, and a leave-untouched list where whitespace is significant. This is the
29
+ coverage mechanism, not a fallback to avoid — but it is explicitly *not* gofmt/rustfmt
30
+ parity.
31
+ 3. **Native-toolchain tier** (ADR 0014, `engines/native_tool/`) — the language's canonical
32
+ first-party CLI, run per file over stdin/stdout. `rustfmt`, `gofmt` and `shellcheck` are
33
+ **on by default whenever the tool is found on PATH**; `zig fmt`, `shfmt`,
34
+ `google-java-format`, `ktfmt`, `styler`, `swift-format`, `dart format`, and
35
+ `gleam format` are opt-in via `[fmt.<lang>.<tool>] enabled = true` /
36
+ `[lint.<lang>.<tool>] enabled = true`. Absent tool ⇒ the language falls through to
37
+ tier 2 with an info-level notice, never an error.
38
+ 4. **`quality`, the code-quality metric tier** (ADR 0027) — cross-cutting, appended to every
39
+ language: file/function/type length, nesting depth, cyclomatic complexity, parameter
40
+ count, and `lazy-ignore`. Warning severity, on by default, configured under
41
+ `[lint.quality]`. The structural rules need a verified node-kind table and cover Python,
42
+ Rust, Go, JavaScript, TypeScript, TSX, Java, Kotlin, C, C++, C#, and Ruby; `magic-number`
43
+ and `law-of-demeter` are opt-in. A per-language deferral table keeps it from duplicating
44
+ a tier-1 rule (ruff's `C901`/`PLR0913`, oxlint's `max-depth`/`max-params`).
45
+ 5. **The built-in ast-grep rule pack** (ADR 0029) — 26 rules across 9 languages (C#, Elixir,
46
+ Go, Java, Kotlin, Python, Ruby, Rust, Swift) embedded in the binary and on by default; 13
47
+ of them ship `severity: off`. It sits *beneath* `[rules] dirs` (default `.poly/rules`), so
48
+ a user rule with the same `id` replaces a pack rule. `[rules] builtin = false` disables
49
+ the pack wholesale.
50
+
51
+ `typos` (spelling) and the opt-in `uncomment` engine are the other two cross-cutting
52
+ backends appended to every language.
53
+
54
+ **Every engine table also accepts a universal `enabled` key**, read by the runner's plan
55
+ rather than by any backend. Whether narrowing a file out of a run charges against
56
+ `--deny-skips` / `--max-skips` follows one rule: **a poly limitation is charged and names the
57
+ limitation; a caller instruction is never charged and always names itself.** `--only`/`--skip`
58
+ and `enabled = false` are caller instructions, so a file they remove is reported as skipped but
59
+ not charged; `no matching engine for this file type`, `no lint rules for <language>`, and a
60
+ generated-file skip are poly's own limitations, and are charged.
61
+
62
+ ## Per-file tier vs whole-project phase
63
+
64
+ `poly lint` runs in two phases:
65
+
66
+ - **Per-file tier** — the parallel, cached engine pass over every discovered file, using the
67
+ five mechanisms above. This is all `--no-workspace` runs.
68
+ - **Whole-project phase** — invokes the same whole-workspace tools a pre-commit hook would
69
+ (`cargo clippy` / `cargo-sort` / `cargo-machete` / `cargo-deny`, plus any inline
70
+ `workspace = true` job such as a type checker) on the live worktree, folding their
71
+ pass/fail into the report and exit code. It reuses the `[hooks]` config as its single
72
+ source of truth. On by default; disable with `--no-workspace` or `[lint] workspace =
73
+ false`. A repo with no `[hooks]` section has no whole-workspace hooks to lower, so it runs
74
+ only the per-file tier.
75
+
76
+ **Plain `poly lint` is not read-only.** poly applies no fixes without `--fix`, but the
77
+ whole-project phase *executes* those tools against the live worktree, and their own side
78
+ effects are not poly's to control (`cargo clippy` populating `target/` or refreshing
79
+ `Cargo.lock`, a `go` invocation appending to `go.work.sum`, a type checker writing its
80
+ cache). Only `--no-workspace` / `[lint] workspace = false` gives a run that cannot touch the
81
+ tree.
82
+
83
+ The phase is also **not path-scoped**: `poly lint <paths>` skips it when the paths *narrow*
84
+ the run, and `--workspace` opts back in with the tools covering the whole repository —
85
+ regardless of the named paths and of `[discovery] exclude`, which filters poly's own
86
+ discovery only. Naming the directory poly is running in (`poly lint .`) is a request for the
87
+ whole project, not a narrowing, so the phase still runs. A note on stderr says which branch
88
+ was taken.
89
+
90
+ Under `--fix`, the whole-project phase runs the tools in fix mode (`cargo sort` in place,
91
+ `cargo-machete --fix`, `cargo clippy --fix --allow-dirty --allow-staged`; `cargo deny` stays
92
+ check-only). Fix mode is what `--fix` adds — the phase runs either way, so `--no-workspace`,
93
+ not the absence of `--fix`, is what skips it. The git-hook / commit-gate path never requests
94
+ fix mode. `poly fmt` never runs this phase.
95
+
96
+ ## Staged isolation (ADR 0019)
97
+
98
+ On the commit-gate path, poly materializes a snapshot of the git **index** (via
99
+ `git checkout-index`) and runs the stage from it, so unstaged edits neither hide nor cause
100
+ failures. Details that matter:
101
+
102
+ - The snapshot is the execution root for **every** hook in the run, not just the
103
+ whole-workspace ones — a gate whose per-file hooks read the worktree while its
104
+ whole-project hooks read the index would report on two different sets of bytes.
105
+ - Isolation is active only for the index stages (`pre-commit`, `pre-merge-commit`) and is
106
+ skipped for `--all-files` (which deliberately checks the whole tree) and for non-index
107
+ stages such as `pre-push`. `[hooks] isolate = false` forces it off.
108
+ - The snapshot lives in the per-user OS cache dir (`~/.cache/poly/<repo-key>/staged`), not
109
+ in-repo, and is refreshed incrementally by index OID so tool caches stay warm.
110
+ - `poly lint`'s whole-project phase is a *different* path: it runs against the live
111
+ worktree, so no snapshot is built.
112
+ - `[hooks] snapshot_include` opts named, git-untracked, repo-relative paths into the snapshot
113
+ by symlinking them in from the live worktree, so a `workspace` hook whose build reads a
114
+ gitignored input (a generated file, a local type-checker config, a downloaded fixture
115
+ directory) does not fail under the gate for a reason the error message doesn't name. Three
116
+ consequences follow from the symlink: a fix to an included file is withheld (there is no
117
+ staged blob to write it into), an included file is never a per-file hook's own input (only
118
+ index content is), and the symlink lets a hook write through into the live worktree.
119
+
120
+ ## Hierarchical poly.toml in monorepos (ADR 0018)
121
+
122
+ Config resolves hierarchically: every `poly.toml` from the repository root down to the file
123
+ being processed is deep-merged, so a nested config layers on top of its ancestors and each
124
+ package can tune rules while sharing a root baseline. The upward walk is bounded at the
125
+ `.git` directory (or an explicit `[workspace] root = true`), so a stray `poly.toml` in
126
+ `$HOME` is never picked up. `poly.local.toml` remains the final local override layer, and a
127
+ top-level `extends` list (ADR 0020) shares sections from local or pinned-remote base
128
+ configs — `poly config update` pins a symbolic remote ref into `poly-config.lock`, and
129
+ `poly config show` prints the effective merged config.
@@ -0,0 +1,10 @@
1
+ <!--
2
+ AI-RULEZ :: GENERATED FILE — DO NOT EDIT
3
+ Content-Hash: blake3:cb19976815fbf90d5f6b6eb13257488eab322f2780265391d895a30e5cc0ff18
4
+ Source-Hash: blake3:840c919261146454e2836095406355dd3ba8664fc068055c202682015400e43f
5
+ Schema-Version: v1
6
+ -->
7
+
8
+ # Concepts
9
+
10
+ * [Poly Tiers And Scope](SKILL.md) - poly's coverage tiers (native / tree-sitter / native-toolchain / quality / built-in ast-grep pack), the per-file tier vs the whole-project phase (--no-workspace), staged isolation (ADR 0019), and hierarchical poly.toml in monorepos (ADR 0018)
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.5
2
+ Name: poly-hermes-plugin
3
+ Version: 0.29.0
4
+ Summary: Zero-dependency lint & format orchestrator over MCP — one pure-Rust binary wrapping ruff/oxc/taplo/rumdl and more as in-process backends, plus a tree-sitter generic tier for everything else. Exposes lint/format/cache tools with structured JSON output.
5
+ Project-URL: Homepage, https://github.com/Goldziher/poly
6
+ Project-URL: Repository, https://github.com/Goldziher/poly
7
+ License-Expression: MIT
8
+ Keywords: code-quality,formatter,linter,mcp,rust
9
+ Requires-Python: >=3.11
10
+ Requires-Dist: mcp==1.28.1
11
+ Requires-Dist: pyyaml==6.0.3
12
+ Description-Content-Type: text/markdown
13
+
14
+ # poly Hermes plugin
15
+
16
+ Zero-dependency lint & format orchestrator over MCP — one pure-Rust binary wrapping ruff/oxc/taplo/rumdl and more as in-process backends, plus a tree-sitter generic tier for everything else. Exposes lint/format/cache tools with structured JSON output.
17
+
18
+ Install this package in the same Python environment as Hermes Agent:
19
+
20
+ ```sh
21
+ python -m pip install poly-hermes-plugin
22
+ ```
23
+
24
+ Enable the plugin through Hermes Agent's plugin configuration. Available registrations depend on the plugin's authored Hermes adapter.
@@ -0,0 +1,19 @@
1
+ poly_hermes_plugin/__init__.py,sha256=TTmehqN7xNwIkpo2hE9u86MMHnDsyfMoqZBILoRZ7dE,385
2
+ poly_hermes_plugin/hermes.py,sha256=AjHDxQ1WFW9l-txFeNSQ9dseTgvOnyhgaa7d19TqWgo,4550
3
+ poly_hermes_plugin/plugin.yaml,sha256=y1IJt71YWVZw3uQLUNeFrmB_IZNMDSRJNvAQMPQwwWQ,407
4
+ poly_hermes_plugin/commands/poly-check.md,sha256=m0GBQKvwIEaL2nRPqBO2KISfEYgrbq21uImQUA6P0bw,2392
5
+ poly_hermes_plugin/commands/poly-fix.md,sha256=1xMCQAgVfYvAq_862xyOFyCDeA15yrFGGMY3ds0MILo,1920
6
+ poly_hermes_plugin/skills/poly-lint-and-format/SKILL.md,sha256=QUocECEYx32QzKEf7VqBq6kGDQsRBUxp7xMPjWPx9Uc,6257
7
+ poly_hermes_plugin/skills/poly-lint-and-format/index.md,sha256=lXaTKLl_qchFml1PcwDA4DBi_TkJpIYR9vkKng8Gemc,466
8
+ poly_hermes_plugin/skills/poly-mcp/SKILL.md,sha256=k9FQ7YHb1H-zqN5WHlGYV3VwyOdAtSjBShQ8rlgKs6s,7054
9
+ poly_hermes_plugin/skills/poly-mcp/index.md,sha256=9J7XDDR3IR9hp3Cm9__uqqIcxvEuH8DIcWHZj_ew87A,464
10
+ poly_hermes_plugin/skills/poly-orchestrator/SKILL.md,sha256=-EvXs4yJp9N2-Pt3Kk9VZEIzDyZdjRO1lfzBI2q8HK4,3625
11
+ poly_hermes_plugin/skills/poly-orchestrator/index.md,sha256=3UuoEWsv99FwhbVVQqpeLSu28eMDX6nAGa08IC5MDN8,470
12
+ poly_hermes_plugin/skills/poly-overview/SKILL.md,sha256=XfLd6nh32SEiE8JwSWhCObnZeShvTD468k9r_va2-Xs,3994
13
+ poly_hermes_plugin/skills/poly-overview/index.md,sha256=RhvI75X2ehnUqYC5f40ou_hfqjFTH6Iu18k8lTQHL0U,428
14
+ poly_hermes_plugin/skills/poly-tiers-and-scope/SKILL.md,sha256=rz8Cbu3WREG3FKrNINr1LkO2WAim1dLFOL4p11ipMNk,8223
15
+ poly_hermes_plugin/skills/poly-tiers-and-scope/index.md,sha256=oaMihgN8uUkAdVWgWY11wFaIL_hZp9rOlRCgvfDMViI,535
16
+ poly_hermes_plugin-0.29.0.dist-info/METADATA,sha256=FuoCI_7vfCQQkpBpc-HylcGbU842kwZYA2GWH7TMzq0,1170
17
+ poly_hermes_plugin-0.29.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
18
+ poly_hermes_plugin-0.29.0.dist-info/entry_points.txt,sha256=lBeJl88Ie_tUFqFbPZ5KqPaVtJ-a1s-Kd4x5Rex-7QI,49
19
+ poly_hermes_plugin-0.29.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [hermes_agent.plugins]
2
+ poly = poly_hermes_plugin