pilot-workers 0.5.3__tar.gz → 0.5.4__tar.gz
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.
- {pilot_workers-0.5.3/src/pilot_workers.egg-info → pilot_workers-0.5.4}/PKG-INFO +3 -3
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/README.md +2 -2
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/pyproject.toml +1 -1
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/cli/install.py +100 -83
- pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/SKILL.md +148 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/code.md +41 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/explore.md +25 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/resume.md +27 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/review.md +37 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/test.md +15 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/codex-host/skills/pilot-workers/SKILL.md +131 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/codex-host/skills/pilot-workers/modes/code.md +38 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/codex-host/skills/pilot-workers/modes/explore.md +22 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/codex-host/skills/pilot-workers/modes/resume.md +25 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/codex-host/skills/pilot-workers/modes/review.md +36 -0
- pilot_workers-0.5.4/src/pilot_workers/integrations/codex-host/skills/pilot-workers/modes/test.md +14 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4/src/pilot_workers.egg-info}/PKG-INFO +3 -3
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers.egg-info/SOURCES.txt +10 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_integrations.py +78 -12
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_skill_generation.py +224 -57
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_worker_prompts.py +1 -1
- pilot_workers-0.5.3/src/pilot_workers/integrations/claude-host/skills/pilot-workers/SKILL.md +0 -256
- pilot_workers-0.5.3/src/pilot_workers/integrations/codex-host/skills/pilot-workers/SKILL.md +0 -231
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/LICENSE +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/setup.cfg +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/__init__.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/__main__.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/cli/__init__.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/cli/dispatch.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/cli/fanout.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/cli/main.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/cli/run.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/cli/status.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/credentials.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/permissions/README.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/permissions/relaxed.yaml +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/permissions/strict.yaml +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/providers/README.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/providers/ds.yaml +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/providers/glm.yaml +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/providers/kimi-k3.yaml +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/templates/code.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/templates/explore.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/templates/review.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/data/templates/test.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/fmt_events.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/integrations/README.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/maintain.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/policy.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/prompts/code.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/prompts/common.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/prompts/explore.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/prompts/review.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/prompts/test.md +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/providers.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/runners/__init__.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/runners/base.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/runners/opencode_runner.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/runtime.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/scripts/install_runtime.sh +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers/taskguard.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers.egg-info/dependency_links.txt +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers.egg-info/entry_points.txt +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers.egg-info/requires.txt +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/src/pilot_workers.egg-info/top_level.txt +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_child_env_hygiene.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_cli_main.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_credentials.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_dispatch.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_fanout.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_fanout_watchdog.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_fmt_events.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_global_key.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_install.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_isolation_guard.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_lock_takeover.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_maintain.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_manifest_locking.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_opencode_runner.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_policy.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_preflight.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_providers.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_render_unified.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_result_extract.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_run_cli.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_runner_cache.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_runner_seams.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_runtime.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_sandbox.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_self_description.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_status.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_status_config.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_task_guards.py +0 -0
- {pilot_workers-0.5.3 → pilot_workers-0.5.4}/tests/test_version_cache.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pilot-workers
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: Dispatch bounded tasks to isolated LLM workers (GLM, Kimi, and more)
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -119,12 +119,12 @@ Reserved keys (cannot be used as provider key): `runner`, `all`, `on`, `for`, `k
|
|
|
119
119
|
|
|
120
120
|
## Host integration
|
|
121
121
|
|
|
122
|
-
The **host** is whatever AI agent acts as the planner. Each host ships ONE `pilot-workers` playbook skill (a doctrine playbook, not provider-specific syntax):
|
|
122
|
+
The **host** is whatever AI agent acts as the planner. Each host ships ONE `pilot-workers` playbook skill (a doctrine playbook, not provider-specific syntax) — a core `SKILL.md` plus five on-demand `modes/<mode>.md` playbooks, so triggering loads the core only and mode craft is read per dispatch:
|
|
123
123
|
|
|
124
124
|
- **`claude-host/skills/pilot-workers/`**: playbook skill for Claude Code (installed to `~/.claude/skills/pilot-workers/`)
|
|
125
125
|
- **`codex-host/skills/pilot-workers/`**: the same playbook skill for Codex (installed to `$CODEX_HOME/skills/pilot-workers/`)
|
|
126
126
|
|
|
127
|
-
`pilot-workers install <provider> on <host>` copies the skill into the host's skill directory and regenerates its worker table from that host's configuration; the doctrine itself carries no engine-specific knowledge. Removing the last provider deletes the skill, so a host with nothing configured has none and the planner does the work itself. (The v0.4.0 12-agents + 8-commands matrix is gone.)
|
|
127
|
+
`pilot-workers install <provider> on <host>` copies the skill into the host's skill directory and regenerates its worker table from that host's configuration; the doctrine itself carries no engine-specific knowledge. The deployed tree is a build artifact — every install re-renders it from the packaged template, so upgrading is `pip` upgrade + `pilot-workers install <host|all>` (hosts with nothing configured are untouched). Removing the last provider deletes the skill, so a host with nothing configured has none and the planner does the work itself. (The v0.4.0 12-agents + 8-commands matrix is gone.)
|
|
128
128
|
|
|
129
129
|
Adding a new host: create `integrations/<name>-host/skills/pilot-workers/`, put whatever config your host needs, point it at `pilot-workers dispatch`. See `integrations/README.md`.
|
|
130
130
|
|
|
@@ -104,12 +104,12 @@ Reserved keys (cannot be used as provider key): `runner`, `all`, `on`, `for`, `k
|
|
|
104
104
|
|
|
105
105
|
## Host integration
|
|
106
106
|
|
|
107
|
-
The **host** is whatever AI agent acts as the planner. Each host ships ONE `pilot-workers` playbook skill (a doctrine playbook, not provider-specific syntax):
|
|
107
|
+
The **host** is whatever AI agent acts as the planner. Each host ships ONE `pilot-workers` playbook skill (a doctrine playbook, not provider-specific syntax) — a core `SKILL.md` plus five on-demand `modes/<mode>.md` playbooks, so triggering loads the core only and mode craft is read per dispatch:
|
|
108
108
|
|
|
109
109
|
- **`claude-host/skills/pilot-workers/`**: playbook skill for Claude Code (installed to `~/.claude/skills/pilot-workers/`)
|
|
110
110
|
- **`codex-host/skills/pilot-workers/`**: the same playbook skill for Codex (installed to `$CODEX_HOME/skills/pilot-workers/`)
|
|
111
111
|
|
|
112
|
-
`pilot-workers install <provider> on <host>` copies the skill into the host's skill directory and regenerates its worker table from that host's configuration; the doctrine itself carries no engine-specific knowledge. Removing the last provider deletes the skill, so a host with nothing configured has none and the planner does the work itself. (The v0.4.0 12-agents + 8-commands matrix is gone.)
|
|
112
|
+
`pilot-workers install <provider> on <host>` copies the skill into the host's skill directory and regenerates its worker table from that host's configuration; the doctrine itself carries no engine-specific knowledge. The deployed tree is a build artifact — every install re-renders it from the packaged template, so upgrading is `pip` upgrade + `pilot-workers install <host|all>` (hosts with nothing configured are untouched). Removing the last provider deletes the skill, so a host with nothing configured has none and the planner does the work itself. (The v0.4.0 12-agents + 8-commands matrix is gone.)
|
|
113
113
|
|
|
114
114
|
Adding a new host: create `integrations/<name>-host/skills/pilot-workers/`, put whatever config your host needs, point it at `pilot-workers dispatch`. See `integrations/README.md`.
|
|
115
115
|
|
|
@@ -495,23 +495,48 @@ def apply_generated_region(skill_text: str, region: str) -> str:
|
|
|
495
495
|
return before + GENERATED_BEGIN + inner + GENERATED_END + after
|
|
496
496
|
|
|
497
497
|
|
|
498
|
+
# Example requests per mode, spliced into the generated description so the
|
|
499
|
+
# trigger has surface area that RESEMBLES real prompts — policy prose shares
|
|
500
|
+
# no tokens with an actual request like asking to trace a flow. Bilingual
|
|
501
|
+
# because users prompt in Chinese too; only ROUTED modes get their examples
|
|
502
|
+
# advertised (the sibling rule to not advertising an unassigned mode's
|
|
503
|
+
# routing). No ": " anywhere — the description must stay a valid plain YAML
|
|
504
|
+
# scalar. resume is planner-internal recovery, so it has no user phrasing.
|
|
505
|
+
MODE_TRIGGER_EXAMPLES: dict[str, tuple[str, ...]] = {
|
|
506
|
+
"explore": ('"how does X work"', '"trace this flow"',
|
|
507
|
+
'"探索/梳理/读一下这块代码"'),
|
|
508
|
+
"code": ('"implement/fix/refactor X"', '"改一下/实现/修复"'),
|
|
509
|
+
"test": ('"run the tests"', '"跑一下测试"'),
|
|
510
|
+
"review": ('"review this change"', '"review 一下这次改动"'),
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
|
|
498
514
|
def render_trigger_sentence(provider_keys: list[str],
|
|
499
515
|
modes: dict[str, str]) -> str:
|
|
500
516
|
"""The frontmatter's trigger clause, generated from the host's ROUTING.
|
|
501
517
|
|
|
502
518
|
This is the only part of the skill a model sees before deciding whether to
|
|
503
|
-
load it, so it decides what the whole feature can do.
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
519
|
+
load it, so it decides what the whole feature can do. Two failure modes are
|
|
520
|
+
on record, both found live:
|
|
521
|
+
|
|
522
|
+
- v0.5.2 read "Trigger when the user names a worker provider — ds, kimi-k3",
|
|
523
|
+
the most specific clause in the description and therefore the operative
|
|
524
|
+
one — so "explore this codebase" never loaded the skill, and the
|
|
525
|
+
mode -> provider table (which lives in the BODY) was never read.
|
|
526
|
+
- v0.5.3 routed by mode but left the judgment open: the surrounding static
|
|
527
|
+
text still said "worth delegating ... Not for small tweaks", so a small
|
|
528
|
+
exploration was judged not worth a worker and the skill never loaded.
|
|
529
|
+
Routing is a MANDATE — ``install ... for <mode>`` is the user making the
|
|
530
|
+
delegation decision once; the sentence must close the per-task
|
|
531
|
+
re-judgment, and the only stated override is explicit user input (the
|
|
532
|
+
top of the priority chain: user input, then config, then do-it-yourself
|
|
533
|
+
fallback).
|
|
534
|
+
|
|
535
|
+
Also load-bearing: NO unquoted colon-space anywhere in the sentence. The
|
|
536
|
+
clause is spliced into a plain YAML scalar, and a mid-value ": " is a
|
|
537
|
+
scanner error in strict YAML — v0.5.3's "Route by MODE, not by name:
|
|
538
|
+
explore" made the whole deployed frontmatter unparseable. A host with no
|
|
539
|
+
assignments routes nothing and must not claim otherwise.
|
|
515
540
|
"""
|
|
516
541
|
names = ", ".join(provider_keys)
|
|
517
542
|
routed: dict[str, list[str]] = {}
|
|
@@ -521,13 +546,28 @@ def render_trigger_sentence(provider_keys: list[str],
|
|
|
521
546
|
if not routed:
|
|
522
547
|
return (f"No mode is routed on this host yet, so nothing is delegated "
|
|
523
548
|
f"automatically; naming a provider ({names}) triggers this skill.")
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
549
|
+
parts = []
|
|
550
|
+
for key, mode_list in sorted(routed.items()):
|
|
551
|
+
head = ", ".join(sorted(mode_list))
|
|
552
|
+
examples = ", ".join(
|
|
553
|
+
ex for m in sorted(mode_list)
|
|
554
|
+
for ex in MODE_TRIGGER_EXAMPLES.get(m, ()))
|
|
555
|
+
suffix = f" (e.g. {examples})" if examples else ""
|
|
556
|
+
parts.append(f"{head} \u2192 {key}{suffix}")
|
|
557
|
+
groups = "; ".join(parts)
|
|
558
|
+
return (f"This host routes work by mode — {groups}. A request for a routed "
|
|
559
|
+
f"kind of work MUST be dispatched through this skill to its "
|
|
560
|
+
f"assigned provider, even when the task looks too small to be "
|
|
561
|
+
f"worth a worker. Never do routed work in this session and never "
|
|
562
|
+
f"weigh whether delegation is worth it — the `install ... for "
|
|
563
|
+
f"<mode>` that created the route already made that decision. The "
|
|
564
|
+
f"route also binds your own mid-task moves — realizing you need "
|
|
565
|
+
f"to read code to understand it, write code, run tests, or "
|
|
566
|
+
f"review a diff means dispatching, not doing it here; only "
|
|
567
|
+
f"verifying a known location (a cited file, a returned diff or "
|
|
568
|
+
f"verdict) stays local. Explicit user input is the only override "
|
|
569
|
+
f"— naming a provider ({names}) selects it, and an explicit "
|
|
570
|
+
f"request to do the work here keeps it here.")
|
|
531
571
|
|
|
532
572
|
|
|
533
573
|
def substitute_trigger_placeholder(skill_text: str,
|
|
@@ -564,36 +604,27 @@ def _packaged_skill_text(host: str) -> str:
|
|
|
564
604
|
/ "SKILL.md").read_text(encoding="utf-8")
|
|
565
605
|
|
|
566
606
|
|
|
567
|
-
def _render_deployed_skill(installs: dict, host: str
|
|
568
|
-
"""The deployed SKILL.md text
|
|
607
|
+
def _render_deployed_skill(installs: dict, host: str) -> str:
|
|
608
|
+
"""The deployed SKILL.md text, rendered from the PACKAGED template.
|
|
569
609
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
610
|
+
The deployed tree is a build artifact: every render starts from package
|
|
611
|
+
data plus the recorded config, so a packaged doctrine update propagates on
|
|
612
|
+
the next install of any form. It used to rebase on the already-deployed
|
|
613
|
+
file to preserve hand edits — which meant a package upgrade could never
|
|
614
|
+
deliver a body update to an existing deployment, while the frontmatter,
|
|
615
|
+
the generated region and every sibling file were rewritten anyway: half a
|
|
616
|
+
promise, and the delivered half was permanent staleness. Custom doctrine
|
|
617
|
+
belongs in the packaged template, where it survives upgrades properly.
|
|
618
|
+
|
|
619
|
+
A packaged template without a marker pair makes ``apply_generated_region``
|
|
620
|
+
raise loudly: that is a packaging bug, never an upgrade state.
|
|
575
621
|
"""
|
|
576
622
|
provider_keys = host_providers(installs, host)
|
|
577
623
|
modes = host_modes(installs, host)
|
|
578
624
|
region = render_worker_region(provider_keys, modes)
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
# No usable marker pair in the deployed text. That is the normal state
|
|
583
|
-
# when upgrading from a release whose skill predates the markers, and it
|
|
584
|
-
# also covers a deployment whose markers were lost to hand-editing —
|
|
585
|
-
# they are HTML comments, invisible in rendered markdown. Fall back to
|
|
586
|
-
# the packaged text, which always carries them. Hand edits in the old
|
|
587
|
-
# file cannot be preserved here: there is no boundary left to preserve
|
|
588
|
-
# them against.
|
|
589
|
-
out = apply_generated_region(_packaged_skill_text(host), region)
|
|
590
|
-
new_front = _frontmatter_block(
|
|
591
|
-
substitute_trigger_placeholder(_packaged_skill_text(host),
|
|
592
|
-
provider_keys, modes))
|
|
593
|
-
old_front = _frontmatter_block(out)
|
|
594
|
-
if new_front is not None and old_front is not None:
|
|
595
|
-
out = new_front + out[len(old_front):]
|
|
596
|
-
return out
|
|
625
|
+
text = substitute_trigger_placeholder(
|
|
626
|
+
_packaged_skill_text(host), provider_keys, modes)
|
|
627
|
+
return apply_generated_region(text, region)
|
|
597
628
|
|
|
598
629
|
|
|
599
630
|
def _host_config_entry(installs: dict, host: str) -> dict:
|
|
@@ -777,33 +808,31 @@ def _deployed_skill_path(entry) -> Path | None:
|
|
|
777
808
|
return None
|
|
778
809
|
|
|
779
810
|
|
|
780
|
-
def
|
|
781
|
-
"""
|
|
811
|
+
def _rerender_deployed_skill(installs: dict, host: str) -> None:
|
|
812
|
+
"""Rewrite the host's already-deployed SKILL.md from the current render.
|
|
782
813
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
the host
|
|
814
|
+
Full re-render from package data (see ``_render_deployed_skill``), written
|
|
815
|
+
to the RECORDED path — this is the path routine provider install/uninstall
|
|
816
|
+
takes, which must not guess a target directory. Sibling files (modes/*.md)
|
|
817
|
+
are converged by the host-form install; this rewrites the one file whose
|
|
818
|
+
content depends on the recorded config. No-op when the host has no
|
|
819
|
+
deployed skill on record.
|
|
787
820
|
"""
|
|
788
821
|
skill = _deployed_skill_path(installs.get(host))
|
|
789
822
|
if skill is None or not skill.is_file():
|
|
790
823
|
return
|
|
791
|
-
# Atomic like every other skill write:
|
|
792
|
-
#
|
|
793
|
-
|
|
794
|
-
_write_skill_atomically(
|
|
795
|
-
skill,
|
|
796
|
-
_render_deployed_skill(installs, host, skill.read_text(encoding="utf-8")))
|
|
824
|
+
# Atomic like every other skill write: a truncating write_text here would
|
|
825
|
+
# leave a crash as a half-written doctrine file nothing detects or repairs.
|
|
826
|
+
_write_skill_atomically(skill, _render_deployed_skill(installs, host))
|
|
797
827
|
|
|
798
828
|
|
|
799
829
|
def _deploy_skill_tree(installs: dict, host: str, target: Path | None) -> None:
|
|
800
|
-
"""Deploy/refresh the host's skill tree
|
|
830
|
+
"""Deploy/refresh the host's skill tree, rendered from package data.
|
|
801
831
|
|
|
802
832
|
Records ``installed_at``/``package_version``/``files``/``created_dirs``
|
|
803
|
-
on the host's manifest entry exactly as the host-install path does.
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
regeneration (the frontmatter is always re-derived from package data).
|
|
833
|
+
on the host's manifest entry exactly as the host-install path does. The
|
|
834
|
+
deployed tree is a build artifact: a refresh converges every file to the
|
|
835
|
+
current packaged render, so package upgrades propagate.
|
|
807
836
|
"""
|
|
808
837
|
entry = installs[host]
|
|
809
838
|
# A legacy v1/v2 nesting must be cleaned by whichever install touches the
|
|
@@ -816,18 +845,16 @@ def _deploy_skill_tree(installs: dict, host: str, target: Path | None) -> None:
|
|
|
816
845
|
for key in [k for k in entry
|
|
817
846
|
if k not in ("providers", "modes")]:
|
|
818
847
|
del entry[key]
|
|
848
|
+
# The previously deployed SKILL.md path: not a render input (the render
|
|
849
|
+
# is pure package data + config), but the orphan sweep below must treat
|
|
850
|
+
# the previous location as in-bounds when --target moves a deployment.
|
|
819
851
|
previous_skill = _deployed_skill_path(entry)
|
|
820
|
-
previous_text: str | None = None
|
|
821
|
-
if previous_skill is not None and previous_skill.is_file():
|
|
822
|
-
previous_text = previous_skill.read_text(encoding="utf-8")
|
|
823
852
|
|
|
824
853
|
# Render BEFORE anything on disk changes. Copying first and rendering after
|
|
825
854
|
# means a render failure leaves the host with a half-updated skill — or none
|
|
826
855
|
# at all on the purge path. Rendering needs no file, so nothing forces that
|
|
827
856
|
# order.
|
|
828
|
-
rendered = _render_deployed_skill(
|
|
829
|
-
installs, host, previous_text if previous_text is not None
|
|
830
|
-
else _packaged_skill_text(host))
|
|
857
|
+
rendered = _render_deployed_skill(installs, host)
|
|
831
858
|
|
|
832
859
|
previous_files = set(entry.get("files") or [])
|
|
833
860
|
result = install_host(host, target, skill_text=rendered)
|
|
@@ -1285,7 +1312,7 @@ def _install_provider_on_host(
|
|
|
1285
1312
|
or not existing.is_file()):
|
|
1286
1313
|
_deploy_skill_tree(installs, host, target)
|
|
1287
1314
|
else:
|
|
1288
|
-
|
|
1315
|
+
_rerender_deployed_skill(installs, host)
|
|
1289
1316
|
if mode is None:
|
|
1290
1317
|
if added:
|
|
1291
1318
|
print(f" recorded: {provider_key} on {host}")
|
|
@@ -1346,18 +1373,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1346
1373
|
print(f"{host}: no workers configured — nothing to install.")
|
|
1347
1374
|
print(f" next: pilot-workers install <provider> on {host}")
|
|
1348
1375
|
continue
|
|
1349
|
-
# Capture the deployed text BEFORE the purge+recopy below, or the
|
|
1350
|
-
# freshly copied package template becomes the splice base and any
|
|
1351
|
-
# prose the user added outside the markers is lost.
|
|
1352
|
-
previous_skill = _deployed_skill_path(previous)
|
|
1353
|
-
previous_text: str | None = None
|
|
1354
|
-
if previous_skill is not None and previous_skill.is_file():
|
|
1355
|
-
previous_text = previous_skill.read_text(encoding="utf-8")
|
|
1356
1376
|
# Render before destroying: a render failure must not leave the host
|
|
1357
1377
|
# with a purged skill and nothing to replace it.
|
|
1358
|
-
rendered = _render_deployed_skill(
|
|
1359
|
-
installs, host, previous_text if previous_text is not None
|
|
1360
|
-
else _packaged_skill_text(host))
|
|
1378
|
+
rendered = _render_deployed_skill(installs, host)
|
|
1361
1379
|
# Migration / reinstall: purge every previous entry for this host
|
|
1362
1380
|
# (v3/v4 flat reinstall OR legacy v1 __all__ + v2 providers), then
|
|
1363
1381
|
# write a clean host-level v4 entry.
|
|
@@ -1380,9 +1398,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1380
1398
|
new_entry["modes"] = previous["modes"]
|
|
1381
1399
|
installs[host] = new_entry
|
|
1382
1400
|
# The deployed skill reflects the recorded configuration; the copy
|
|
1383
|
-
# above already wrote the text rendered from
|
|
1384
|
-
#
|
|
1385
|
-
# markers and the frontmatter survive).
|
|
1401
|
+
# above already wrote the text rendered from package data plus
|
|
1402
|
+
# that configuration.
|
|
1386
1403
|
# The manifest is committed ONCE, when the transaction exits — not
|
|
1387
1404
|
# per host. A crash mid-``install all`` therefore records no hosts,
|
|
1388
1405
|
# rather than some: the deployed files of the completed hosts are
|
|
@@ -1421,7 +1438,7 @@ def _uninstall_provider_on_host(provider_key: str, host: str) -> int:
|
|
|
1421
1438
|
return 0
|
|
1422
1439
|
entry = installs.get(host)
|
|
1423
1440
|
if host_providers(installs, host):
|
|
1424
|
-
|
|
1441
|
+
_rerender_deployed_skill(installs, host)
|
|
1425
1442
|
elif isinstance(entry, dict) and isinstance(entry.get("files"), list):
|
|
1426
1443
|
# That was the last provider: purge the deployed skill and drop
|
|
1427
1444
|
# the host's manifest entry entirely.
|
|
@@ -1458,7 +1475,7 @@ def _uninstall_default_on_host(mode: str, host: str) -> int:
|
|
|
1458
1475
|
try:
|
|
1459
1476
|
with manifest_transaction(delete_when_empty=True) as installs:
|
|
1460
1477
|
if clear_host_mode(installs, host, mode):
|
|
1461
|
-
|
|
1478
|
+
_rerender_deployed_skill(installs, host)
|
|
1462
1479
|
print(f" removed: {mode} assignment on {host}")
|
|
1463
1480
|
else:
|
|
1464
1481
|
print(f"note: no provider assigned to mode {mode!r} on {host}")
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pilot-workers
|
|
3
|
+
description: Dispatch bounded tasks (code, explore, test, review, resume) to isolated LLM workers via the pilot-workers CLI and harvest their structured verdicts. {{PILOT_PROVIDER_TRIGGERS}}
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# pilot-workers Playbook
|
|
7
|
+
|
|
8
|
+
You are the planner. Workers are separate OpenCode processes that **cannot see
|
|
9
|
+
this conversation**. Planning, task decomposition, and final verification stay
|
|
10
|
+
with you; workers get only settled decisions.
|
|
11
|
+
|
|
12
|
+
## When this skill applies
|
|
13
|
+
|
|
14
|
+
Two kinds of moments route here; match either, then choose the provider by
|
|
15
|
+
the priority chain below.
|
|
16
|
+
|
|
17
|
+
| Moment | Mode |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| "how does X work" / "trace this flow" / "探索、梳理、理解、读一下这块代码" — or YOU need to read code to build understanding before planning | explore |
|
|
20
|
+
| "implement/fix/refactor X" / "改一下、实现、修复" — or the plan is settled and edits would begin | code |
|
|
21
|
+
| "run the tests" / "跑一下测试" — or you want a suite run to verify a change | test |
|
|
22
|
+
| "review this change" / "review 一下这次改动" — or a rewrite-scale diff just landed | review |
|
|
23
|
+
| a prior dispatch failed or stopped short | resume |
|
|
24
|
+
|
|
25
|
+
The self-initiated rows draw the line by PURPOSE, never by size: reading to
|
|
26
|
+
LEARN (trace a flow, understand a module, gather context for a change) is an
|
|
27
|
+
explore dispatch no matter how few files; verifying a KNOWN location (a cited
|
|
28
|
+
file:line, a returned diff, a verdict) is local reading and needs no worker.
|
|
29
|
+
|
|
30
|
+
## Quick Reference
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pilot-workers template <mode> > /tmp/<provider>-<mode>-<slug>-<timestamp>.md # fill it in — self-contained
|
|
34
|
+
pilot-workers dispatch --provider <key> --mode <mode> --workdir "$PWD" --task-file <file> # background Bash
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Choose `<key>` by priority.** (1) Explicit user input always wins: a provider
|
|
38
|
+
the user names is used even where the Workers table assigns another, and an
|
|
39
|
+
explicit request to do the work here ("don't dispatch", "do it yourself") keeps
|
|
40
|
+
it in this session. (2) Otherwise the **Workers table** at the bottom of this
|
|
41
|
+
file decides: a routed mode is ALWAYS dispatched to its assigned provider —
|
|
42
|
+
never done in this session, and never weighed for whether it is worth a worker.
|
|
43
|
+
`install ... for <mode>` was the user making that economics decision once; it
|
|
44
|
+
is not yours to remake per task. If a routed dispatch seems wasteful, dispatch
|
|
45
|
+
anyway and say so afterwards — the user can
|
|
46
|
+
`pilot-workers uninstall for <mode> on <host>`. (3) **A mode with no provider
|
|
47
|
+
assigned is not an invitation to guess: do it yourself, in this session.** No
|
|
48
|
+
assignment means the user never delegated that kind of work; picking a worker
|
|
49
|
+
by its advertised strengths would delegate something they chose to keep. If a
|
|
50
|
+
mode looks worth delegating, say so and let them run
|
|
51
|
+
`pilot-workers install <provider> on <host> for <mode>`. Never dispatch to a
|
|
52
|
+
provider absent from the table: it was not configured here.
|
|
53
|
+
|
|
54
|
+
**Then Read `modes/<mode>.md`** (next to this file in the skill directory)
|
|
55
|
+
before writing the task file — it is that mode's task recipe and verification
|
|
56
|
+
contract. Never dispatch a mode whose playbook you have not read in this
|
|
57
|
+
session.
|
|
58
|
+
|
|
59
|
+
- stdout is exactly two JSON lines: first `worker_runner.started` (record
|
|
60
|
+
run_id and log paths), last `worker_runner.verdict`. **The completion signal
|
|
61
|
+
= the background Bash exiting on its own.** Never poll by process name;
|
|
62
|
+
never judge from the shared log (`latest.log` is for humans only). Fewer than
|
|
63
|
+
two lines means the run died before starting — read its stderr, because an
|
|
64
|
+
early failure (missing credential, runner not installed) emits no JSON at all.
|
|
65
|
+
- **Dispatch from the main session only, in a background Bash.** Subagents die
|
|
66
|
+
at turn end and their background tasks are never harvested — never dispatch
|
|
67
|
+
from a subagent, never "wait" by ending your turn.
|
|
68
|
+
- Consumption contract: read `verdict.result` first (the parsed PILOT_RESULT
|
|
69
|
+
block). Read `final_text_path` at most once, only when
|
|
70
|
+
`parse_state != "parsed"` or a finding requires surrounding context. Never
|
|
71
|
+
auto-redispatch on parse failure alone.
|
|
72
|
+
- Resume-first recovery: on failure or non-convergence, resume with
|
|
73
|
+
`--session <session_id>` + `--run-id <resume_run_id>` from the original verdict
|
|
74
|
+
before considering a cold redispatch. A `credential missing` error is not a
|
|
75
|
+
worker failure and resume will not fix it — the provider has no API key yet:
|
|
76
|
+
tell the user to run
|
|
77
|
+
`pilot-workers install <provider> on <host> --global-key`, which prompts for
|
|
78
|
+
it. The key belongs to the provider, so it is configured once for every host.
|
|
79
|
+
Never handle a key yourself.
|
|
80
|
+
|
|
81
|
+
## Verdict matrix
|
|
82
|
+
|
|
83
|
+
The `verdict` state string and the sibling flags `timed_out` / `idle_timed_out` /
|
|
84
|
+
`interrupted` are set independently — **check the flags even on `completed`**.
|
|
85
|
+
|
|
86
|
+
| state | meaning | action |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `completed` | usable report (`parse_state` parsed, or long unstructured text) | consume `result` first; flags may still be set — say so |
|
|
89
|
+
| `step_capped_partial` | step cap hit | partial coverage; a parsed partial block is still salvaged into `result` — report the uncovered scope truthfully |
|
|
90
|
+
| `error` | summary-error or crash with no usable text | `stderr_tail` first; open `jsonl_path` only if it does not explain the death |
|
|
91
|
+
| `empty` | no usable output | same: `stderr_tail`, then `jsonl_path` if needed |
|
|
92
|
+
|
|
93
|
+
Never draw a conclusion without reading the evidence.
|
|
94
|
+
|
|
95
|
+
`duration_s` / `tokens` / `final_text_len` are for your next decision, not the
|
|
96
|
+
report: cost so far, and whether `final_text_path` is worth opening at all
|
|
97
|
+
(`parse_state: parsed` means `result` already has everything).
|
|
98
|
+
|
|
99
|
+
`parse_state` values: `parsed` (consume `result`), `malformed` (the worker DID
|
|
100
|
+
write a result block and it did not parse — the work is real, read
|
|
101
|
+
`final_text_path`), `unstructured` (a block that was cut off mid-write — treat as
|
|
102
|
+
partial), `unavailable` (no block at all — the worker ignored the contract).
|
|
103
|
+
|
|
104
|
+
Synthesized fanout verdicts carry `synthesized: true` + `reason`
|
|
105
|
+
(`crash|timeout|idle_timeout|interrupted`) + `stderr_tail`; `result` and
|
|
106
|
+
`final_text_path` are null. Consume rule: synthesized → read `reason` +
|
|
107
|
+
`stderr_tail` only.
|
|
108
|
+
|
|
109
|
+
## Task files
|
|
110
|
+
|
|
111
|
+
- The worker sees nothing but the task file: it must be **self-contained** —
|
|
112
|
+
explicit file paths, completion criteria, do-not-touch boundaries. Never
|
|
113
|
+
"that file" or "the module mentioned above".
|
|
114
|
+
- Unique `/tmp` names (`<provider>-<mode>-<slug>-<timestamp>.md`) so parallel
|
|
115
|
+
sessions never clobber each other.
|
|
116
|
+
- **Never any credentials** in a task file — it is sent verbatim to a
|
|
117
|
+
third-party endpoint. Dispatch refuses obvious key shapes and any key
|
|
118
|
+
configured on this machine, but that check **cannot catch every secret**:
|
|
119
|
+
it is a backstop, not permission to paste config. Reference a value by
|
|
120
|
+
env var and let the worker read it.
|
|
121
|
+
- **The worker can see the whole workdir.** Opening an `auth.json` or `.env` is
|
|
122
|
+
denied for both the shell and the read tool, but a path deny cannot stop a
|
|
123
|
+
recursive content search from returning a line out of one. If the project holds
|
|
124
|
+
live secrets in untracked files, dispatch with `--worktree`: a detached
|
|
125
|
+
worktree materialises tracked files only, so a gitignored `.env` is not there
|
|
126
|
+
at all — a boundary rather than a pattern.
|
|
127
|
+
- General discipline does not need to be written — dispatch injects
|
|
128
|
+
`prompts/*.md` automatically, including the `PILOT_RESULT` output block the
|
|
129
|
+
worker must end with.
|
|
130
|
+
|
|
131
|
+
<!--PILOT_GENERATED_BEGIN-->
|
|
132
|
+
<!--PILOT_GENERATED_END-->
|
|
133
|
+
|
|
134
|
+
## Providers
|
|
135
|
+
|
|
136
|
+
Provider strengths and suitable modes live in the provider YAML registry,
|
|
137
|
+
not here — run `pilot-workers status <host>` when you need them (status
|
|
138
|
+
renders each provider's `strengths`, `suitable_modes`, and `notes` live).
|
|
139
|
+
|
|
140
|
+
## Timeouts
|
|
141
|
+
|
|
142
|
+
- `--timeout <sec>` caps the whole job; the fanout parent watchdog
|
|
143
|
+
enforces it plus a grace period.
|
|
144
|
+
- **`--timeout 0` forfeits the parent watchdog** for that job (no deadline,
|
|
145
|
+
no silence kill); the child's `--idle-timeout` remains the only liveness
|
|
146
|
+
bound.
|
|
147
|
+
- `--timeout 0 --idle-timeout 0` together make a job **fully unbounded** —
|
|
148
|
+
avoid unless you are watching it yourself.
|
pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/code.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Mode: code — dispatch playbook
|
|
2
|
+
|
|
3
|
+
(Read this before every code dispatch. The core SKILL.md holds the
|
|
4
|
+
priority chain, the red lines and the verdict contract; this file
|
|
5
|
+
holds the craft for this one mode.)
|
|
6
|
+
|
|
7
|
+
- **Shape the task; the dispatch decision is already made.** Routing (or the
|
|
8
|
+
user naming a provider) decided who does code work — what stays yours is
|
|
9
|
+
making the task carryable: settle every judgment call before dispatch
|
|
10
|
+
(workers get only settled decisions) and hand over specs, not questions. A
|
|
11
|
+
change that would need mid-course judgment at every step is a planning gap —
|
|
12
|
+
settle more, then dispatch.
|
|
13
|
+
- One worker call bundles at most 2-3 related fix points; split larger
|
|
14
|
+
batches into multiple workers (they can run in parallel).
|
|
15
|
+
- **Parallel code jobs require `--worktree`** so each worker gets an isolated
|
|
16
|
+
git worktree; one worker per background Bash; batch similar durations per
|
|
17
|
+
fanout and split mixed durations. Clean up with
|
|
18
|
+
`pilot-workers maintain worktrees remove <path>`.
|
|
19
|
+
- Verify once, and verify what is cheap to verify COMPLETELY. `git diff --stat`
|
|
20
|
+
plus `git status --short` settle one whole property for a few hundred tokens:
|
|
21
|
+
which files changed. Compare that set against the spec's whitelist — anything
|
|
22
|
+
outside it is a boundary violation, and a stray untracked file is worth
|
|
23
|
+
catching too. Reconcile the worker's own `FILES_CHANGED` against that set too — a
|
|
24
|
+
mismatch means it misreported its work, which colours everything else it
|
|
25
|
+
claimed. Also read `exit_code` / `session_id` / `steps` / `tool_errors`
|
|
26
|
+
from the verdict.
|
|
27
|
+
- **Do not sample the diff.** Reading a few hunks of a large change licenses
|
|
28
|
+
nothing about the rest; it costs attention and buys confidence you have not
|
|
29
|
+
earned. Correctness comes from the test run, from exercising the behaviour
|
|
30
|
+
end to end, and — for rewrite-scale diffs — from the cross-model review below.
|
|
31
|
+
Never treat the worker's completion claim as proof. **The test run goes to whichever provider is
|
|
32
|
+
assigned to `test` in the Workers table**, as a `test`-mode dispatch; running
|
|
33
|
+
it here would void that assignment. You still read the counts and failures and
|
|
34
|
+
decide what they mean.
|
|
35
|
+
- **Cross-model review for rewrite-scale diffs** (several hundred lines or more):
|
|
36
|
+
dispatch a *different* provider in review mode before verifying — the two
|
|
37
|
+
models' errors are uncorrelated, so the second catches the first's
|
|
38
|
+
systematic blind spots at cheap quota. Skip for small changes.
|
|
39
|
+
- Do not edit a worker's target files while it is running. Deletion,
|
|
40
|
+
migration, CI/keys/production config changes: do not dispatch; a human does
|
|
41
|
+
those.
|
pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/explore.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Mode: explore — dispatch playbook
|
|
2
|
+
|
|
3
|
+
(Read this before every explore dispatch. The core SKILL.md holds the
|
|
4
|
+
priority chain, the red lines and the verdict contract; this file
|
|
5
|
+
holds the craft for this one mode.)
|
|
6
|
+
|
|
7
|
+
Reading code is the bulk of token spend (read-to-write ratio roughly 50:1), so
|
|
8
|
+
exploration is a top dispatch candidate. Write the question straight into the
|
|
9
|
+
task file; do not read the code yourself first — that wastes the saving.
|
|
10
|
+
|
|
11
|
+
- List what to investigate item by item; pin the scope to specific
|
|
12
|
+
directories/file types to shrink roaming room.
|
|
13
|
+
- **Planning is the verification — do not sample.** Sampling a couple of
|
|
14
|
+
conclusions proves nothing about the rest and manufactures confidence in it.
|
|
15
|
+
Instead take the report into planning; the gaps surface as you use it:
|
|
16
|
+
a broad gap (wrong subsystem, missing the leads you need) goes back as a
|
|
17
|
+
rewritten explore dispatch, while three or five lines you still need — read
|
|
18
|
+
them here, a round-trip costs more than the read.
|
|
19
|
+
- Conclusions carrying no `file:line` are untrusted: you cannot plan on them and
|
|
20
|
+
cannot check them, so treat them as absent.
|
|
21
|
+
- Bring conclusions back **with their file:line references, verbatim** — the
|
|
22
|
+
main thread requires those references to plan; losing them ruins everything.
|
|
23
|
+
- Boundary: judgment/trade-off questions ("which approach is better") are your
|
|
24
|
+
job, not the worker's. Mixed explore+change tasks: explore first, plan,
|
|
25
|
+
then dispatch code.
|
pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/resume.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Mode: resume — dispatch playbook
|
|
2
|
+
|
|
3
|
+
(Read this before every resume dispatch. The core SKILL.md holds the
|
|
4
|
+
priority chain, the red lines and the verdict contract; this file
|
|
5
|
+
holds the craft for this one mode.)
|
|
6
|
+
|
|
7
|
+
- **Resume-first recovery.** When a run fails or does not converge, prefer
|
|
8
|
+
resume — it reuses the full prior-session context and saves minute-scale
|
|
9
|
+
round-trips versus a cold restart:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pilot-workers dispatch --provider <key> --mode resume \
|
|
13
|
+
--session <session_id from the verdict> --run-id <resume_run_id from the verdict> \
|
|
14
|
+
--workdir <workdir from started> --task "Previous task incomplete: <what is missing, how to fix>"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Take `--session` from the verdict and `--run-id` from its **`resume_run_id`**,
|
|
18
|
+
not its `run_id`: a resumed run gets a fresh `run_id` for its own log, so
|
|
19
|
+
resuming twice off `run_id` names a sandbox that never existed and fails as
|
|
20
|
+
"session expired". `resume_run_id` is the sandbox, and for a cold run the two
|
|
21
|
+
are equal — so read that one field either way. No template for resume — pass
|
|
22
|
+
`--task` with what remains and how to fix it.
|
|
23
|
+
- **Two obstacles, then take over**: if the worker hits the same obstacle
|
|
24
|
+
twice and still does not pass → the main session takes over and wraps up.
|
|
25
|
+
- The resume window == the sandbox retention window. A loud "session expired
|
|
26
|
+
past retention" error means the sandbox was reaped — redispatch cold. A
|
|
27
|
+
loud "run is still active" error means a live lock; do not force it.
|
pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/review.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Mode: review — dispatch playbook
|
|
2
|
+
|
|
3
|
+
(Read this before every review dispatch. The core SKILL.md holds the
|
|
4
|
+
priority chain, the red lines and the verdict contract; this file
|
|
5
|
+
holds the craft for this one mode.)
|
|
6
|
+
|
|
7
|
+
- **Axis-splitting is your judgment call.** Fix 2-4 orthogonal axes
|
|
8
|
+
(correctness/boundary conditions, security, performance, consistency with
|
|
9
|
+
codebase conventions); one instance handles exactly one axis. Write each
|
|
10
|
+
axis as its own self-contained task file.
|
|
11
|
+
- **Parallel fanout recipe**: one job per axis, launched together —
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pilot-workers fanout --job <providerA>:review:/tmp/review-correctness-<ts>.md \
|
|
15
|
+
--job <providerB>:review:/tmp/review-security-<ts>.md
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
(`--job PROVIDER:MODE:TASK_FILE`; mixing providers distributes load across
|
|
19
|
+
quotas.) Each job collects its verdict independently.
|
|
20
|
+
- **Aggregation is your job.** Merge and dedupe findings across axes, sort by
|
|
21
|
+
severity, report directly. **Verify every finding you intend to act on,
|
|
22
|
+
before acting** — not a sample of them. A review finding is a claim you will
|
|
23
|
+
answer by editing code, so a false positive turns into a wrong edit; open its
|
|
24
|
+
cited `file:line` and confirm the defect is real. Findings you are NOT acting
|
|
25
|
+
on need no verification: say they are unverified. Findings with no `file:line`
|
|
26
|
+
are untrusted.
|
|
27
|
+
- **Try to REFUTE each high before acting on it, and refute its fix too.**
|
|
28
|
+
Reviewers cannot run code (interpreters are denied in review mode), so their
|
|
29
|
+
findings are readings — plausible and sometimes wrong. Run the thing: the
|
|
30
|
+
input against the regex, the race with the lock disabled, the command in a
|
|
31
|
+
scratch copy. A proposed fix is a separate claim and has been wrong even when
|
|
32
|
+
the diagnosis was right. For a high you cannot settle by running something,
|
|
33
|
+
dispatch a *different* provider in review mode to argue against it.
|
|
34
|
+
- Review mode cannot edit; fixes go through your planning — small fixes
|
|
35
|
+
yourself, bulk mechanical fixes via a code dispatch.
|
|
36
|
+
- Axis too broad ("review the entire repo") → split axes first; unclear diff
|
|
37
|
+
baseline → clarify the two versions being compared first.
|
pilot_workers-0.5.4/src/pilot_workers/integrations/claude-host/skills/pilot-workers/modes/test.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Mode: test — dispatch playbook
|
|
2
|
+
|
|
3
|
+
(Read this before every test dispatch. The core SKILL.md holds the
|
|
4
|
+
priority chain, the red lines and the verdict contract; this file
|
|
5
|
+
holds the craft for this one mode.)
|
|
6
|
+
|
|
7
|
+
- The task states the exact test command, directory, preconditions, and any
|
|
8
|
+
known pre-existing failures. Run-and-gather only; fixes are your job.
|
|
9
|
+
- **Anti-false-positive**: counts + raw error text → trust it. "All passed"
|
|
10
|
+
with no counts → suspicious → read `jsonl_path` to see what command
|
|
11
|
+
actually ran, and redispatch if needed. Run `git status` to confirm the
|
|
12
|
+
worker left no junk changes behind.
|
|
13
|
+
- Bring counts and the failure list (test name, raw error text, `file:line`)
|
|
14
|
+
back verbatim; do not interpret root cause or propose fixes on the worker's
|
|
15
|
+
behalf.
|