From f42eba659da83e02fd10f73e74b53d468309bc70 Mon Sep 17 00:00:00 2001 From: Kyle Merritt Date: Fri, 13 Nov 2026 13:48:44 -0500 Subject: [PATCH 1/3] Extend planner scope with replaceable checklist and presentation --- README.md | 2 +- packages/planner-scope/SKILL.md | 4 ++- packages/planner-scope/relayview-skill.json | 11 ++++--- packages/planner-scope/scope.md | 35 +++++++++++++++++++++ tests/test_packages.py | 10 ++++++ tools/packages.py | 15 +++++++-- 6 files changed, 69 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index eae9ce7..b6c835a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Public source for RelayView-maintained instruction-only role skills and an illus | Directory | Status | Role / step | Version | | --- | --- | --- | --- | | `packages/{planner,implementer,reviewer}-investigation` | Maintained automatic guidance | One matching role / step each | 0.7.0 | -| `packages/planner-scope` | Maintained default | Planner / planning | 0.2.0 | +| `packages/planner-scope` | Maintained default | Planner / planning | 0.8.0 | | `packages/implementer-handoff` | Maintained default | Implementer / implementation | 0.2.0 | | `packages/issue-designer-default` | Maintained default | Designer / design | 0.6.1 | | `packages/designer-wayfinder`, `designer-grilling` | Optional manual guidance | Designer / design | 0.6.0 | diff --git a/packages/planner-scope/SKILL.md b/packages/planner-scope/SKILL.md index 3e59146..a47cc62 100644 --- a/packages/planner-scope/SKILL.md +++ b/packages/planner-scope/SKILL.md @@ -3,7 +3,7 @@ name: planner-scope description: Check assigned issue scope, neighboring work, and verification before drafting a Plan. metadata: relayview-display-name: Planner scope - relayview-version: 0.2.0 + relayview-version: 0.8.0 --- # Planner scope @@ -13,3 +13,5 @@ When drafting the assigned Plan, identify the requested behavior, its boundary, If the owner supplies an admitted work-item identity, use the assigned read tools to inspect it. Preserve source attribution; an issue description is a request, not evidence that its proposed behavior exists. Where tracker access is unavailable, state the missing context instead of guessing a work-item identity. Write the Plan through the owner's assigned planning interface. The Plan is ready when each requested outcome has an implementation boundary and a checkable success or recovery observation. Owner-controlled workflow stages and checks determine execution authority. + +For a linked Gitea issue, this package declares the owner's transition from `status/ready-for-agent` to `status/in-progress` after it proves that the exact Plan reached the Implementer. Finalize the Plan through the assigned interface, then use owner-reported handoff and issue-claim outcomes when explaining progress to the Operator. An accepted Plan alone does not establish that claim. A user may replace this skill with a Planner fork whose package declares a different target status or disables the claim; follow the selected package's policy recorded for the task. diff --git a/packages/planner-scope/relayview-skill.json b/packages/planner-scope/relayview-skill.json index a4c6243..035261d 100644 --- a/packages/planner-scope/relayview-skill.json +++ b/packages/planner-scope/relayview-skill.json @@ -1,19 +1,22 @@ { - "schemaVersion": 1, + "schemaVersion": 2, "source": { "kind": "first-party", - "reference": "v0.2.0" + "reference": "v0.8.0" }, "role": "planner", "step": "planning", + "issueClaim": { + "statusLabel": "status/in-progress" + }, "files": [ { "path": "SKILL.md", - "sha256": "31399ba322d8a4d3ed9814e7fd5d54883b4773c5b7dc3a241b8e14f8f7c16072" + "sha256": "7dbd2ace7472a75c69b70ea118333429dfc7d56e5374454724805aa783cc0112" }, { "path": "scope.md", - "sha256": "fc365d5f5c90f878992204235f32b1148aa4934a31f8c10eb063292fb64cf248" + "sha256": "abed1a1590273b5f62f1e1f47ba8c92d00693de72c0d5e9b014ed1c911ac0a8e" } ] } diff --git a/packages/planner-scope/scope.md b/packages/planner-scope/scope.md index 0c329f1..1acd63c 100644 --- a/packages/planner-scope/scope.md +++ b/packages/planner-scope/scope.md @@ -6,3 +6,38 @@ - Distinguish verified current behavior from a proposal. - Identify one observable success path and one meaningful failure or recovery path. - Record uncertainty as an open decision; do not turn silence into approval. + +Focus on: +- affected files and symbols +- existing patterns and architecture +- invariants and edge cases +- ordering and dependencies between changes +- tests, validation, and likely failure modes +- any assumptions that the implementer must know +- explicitly authorized supporting context that influences behavior + +Return a compact structured plan. Prefer YAML-compatible Markdown: + +```yaml +objective: ... +constraints: + - ... +steps: + - id: ... + files: + - ... + symbols: + - ... + change: ... + requirements: + - ... + depends_on: + - ... +edge_cases: + - ... +validation: + - ... +open_questions: + - ... +``` + diff --git a/tests/test_packages.py b/tests/test_packages.py index 6ff16db..d421126 100644 --- a/tests/test_packages.py +++ b/tests/test_packages.py @@ -12,6 +12,16 @@ ROOT = Path(__file__).resolve().parents[1] class PackageTests(unittest.TestCase): + def test_planner_scope_presentation_and_claim(self): + package = ROOT / "packages/planner-scope" + check_package(package) + text = (package / "scope.md").read_text() + for phrase in ("affected files and symbols", "invariants and edge cases", "YAML-compatible Markdown", "open_questions:"): + self.assertIn(phrase, text) + self.assertNotIn("follow-up monitor", text) + manifest = json.loads((package / "relayview-skill.json").read_text()) + self.assertEqual(manifest["issueClaim"], {"statusLabel": "status/in-progress"}) + def test_role_investigation_packages(self): for role, step in (("planner", "planning"), ("implementer", "implementation"), ("reviewer", "review")): package = ROOT / "packages" / f"{role}-investigation" diff --git a/tools/packages.py b/tools/packages.py index 8ee40ce..6aa147c 100644 --- a/tools/packages.py +++ b/tools/packages.py @@ -44,15 +44,26 @@ def check_package(path): manifest = json.loads(_text(raw_manifest, str(sidecar))) except (ValueError, TypeError) as error: _fail(f"{sidecar}: invalid JSON: {error}") - if not isinstance(manifest, dict) or set(manifest) != {"schemaVersion", "source", "role", "step", "files"}: + if not isinstance(manifest, dict) or ( + (manifest.get("schemaVersion") == 1 and set(manifest) != {"schemaVersion", "source", "role", "step", "files"}) or + (manifest.get("schemaVersion") == 2 and set(manifest) != {"schemaVersion", "source", "role", "step", "files", "issueClaim"}) or + manifest.get("schemaVersion") not in (1, 2) + ): _fail(f"{path}: unsupported manifest fields") source = manifest["source"] if not isinstance(source, dict) or set(source) != {"kind", "reference"}: _fail(f"{path}: invalid source") if source["kind"] not in ("first-party", "user") or not isinstance(source["reference"], str) or not re.fullmatch(r"[A-Za-z0-9._:-]{1,128}", source["reference"]): _fail(f"{path}: invalid source identity") - if manifest["schemaVersion"] != 1 or (manifest["role"], manifest["step"]) not in (("planner", "planning"), ("implementer", "implementation"), ("reviewer", "review"), ("designer", "design")): + if (manifest["role"], manifest["step"]) not in (("planner", "planning"), ("implementer", "implementation"), ("reviewer", "review"), ("designer", "design")): _fail(f"{path}: incompatible role or step") + if manifest["schemaVersion"] == 2: + claim = manifest["issueClaim"] + label = claim.get("statusLabel") if isinstance(claim, dict) else None + if (manifest["role"], manifest["step"]) != ("planner", "planning") or not isinstance(claim, dict) or set(claim) != {"statusLabel"} or ( + label is not None and (not isinstance(label, str) or not re.fullmatch(r"status/[a-z][a-z0-9-]{0,63}", label) or label == "status/ready-for-agent") + ): + _fail(f"{path}: invalid issue claim policy") files = manifest["files"] if not isinstance(files, list) or not 1 <= len(files) <= 16: _fail(f"{path}: invalid file list") From 2d7bf2404ae34b4a6a115c8774c853ff8ae47984 Mon Sep 17 00:00:00 2001 From: Kyle Merritt Date: Fri, 13 Nov 2026 13:51:48 -0500 Subject: [PATCH 2/3] Align maintained package fixture with planner scope release --- tests/test_packages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_packages.py b/tests/test_packages.py index d421126..f5edb31 100644 --- a/tests/test_packages.py +++ b/tests/test_packages.py @@ -113,7 +113,7 @@ class PackageTests(unittest.TestCase): package = ROOT / "packages" / name manifest = json.loads((package / "relayview-skill.json").read_text()) self.assertEqual((manifest["role"], manifest["step"]), (role, step)) - self.assertEqual(manifest["source"], {"kind": "first-party", "reference": "v0.2.0"}) + self.assertEqual(manifest["source"], {"kind": "first-party", "reference": "v0.8.0" if name == "planner-scope" else "v0.2.0"}) self.assertIn(resource, [item["path"] for item in manifest["files"]]) self.assertIn(marker, (package / "SKILL.md").read_text() + (package / resource).read_text()) From 64164444e68adfe6d88ceaa1513e3ae7220b6048 Mon Sep 17 00:00:00 2001 From: Kyle Merritt Date: Fri, 13 Nov 2026 16:03:24 -0500 Subject: [PATCH 3/3] Correct release verification and document claim schema --- README.md | 4 ++-- packages/planner-scope/SKILL.md | 2 +- packages/planner-scope/relayview-skill.json | 4 ++-- tests/test_packages.py | 24 ++++++++++++++++++++- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b6c835a..1f93fa3 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Public source for RelayView-maintained instruction-only role skills and an illus | Directory | Status | Role / step | Version | | --- | --- | --- | --- | | `packages/{planner,implementer,reviewer}-investigation` | Maintained automatic guidance | One matching role / step each | 0.7.0 | -| `packages/planner-scope` | Maintained default | Planner / planning | 0.8.0 | +| `packages/planner-scope` | Maintained default | Planner / planning | 0.8.1 | | `packages/implementer-handoff` | Maintained default | Implementer / implementation | 0.2.0 | | `packages/issue-designer-default` | Maintained default | Designer / design | 0.6.1 | | `packages/designer-wayfinder`, `designer-grilling` | Optional manual guidance | Designer / design | 0.6.0 | @@ -35,7 +35,7 @@ Public source for RelayView-maintained instruction-only role skills and an illus | `packages/c4-diff` | Optional guidance | Reviewer / review | 0.3.0 | | `examples/starter-planner` | Illustrative starter; not a production default | Planner / planning | 0.1.0 | -Only named releases of maintained packages receive RelayView compatibility testing and maintenance. Optional guidance requires explicit role assignment; the Planner and Implementer defaults remain available alongside the pinned Issue Designer default. User forks are maintained by their publishers. This release uses the instruction package schema version 1 admitted by RelayView's Community MVP. It contains only `SKILL.md`, declared `.md`/`.txt` resources, and `relayview-skill.json` within each package. Scripts, executable files, undeclared files, and requested permissions fail checks and owner admission. There is no fixed release calendar: maintained packages are versioned when their content or compatibility changes. A breaking owner contract requires a new compatible maintained release before the product depends on it. +Only named releases of maintained packages receive RelayView compatibility testing and maintenance. Optional guidance requires explicit role assignment; the Planner and Implementer defaults remain available alongside the pinned Issue Designer default. User forks are maintained by their publishers. Instruction packages use schema version 1, or schema version 2 for a Planner package declaring owner-validated `issueClaim` metadata. Schema 2 accepts a nullable target status label; the owner enforces the claim transition after proved implementation handoff. It contains only `SKILL.md`, declared `.md`/`.txt` resources, and `relayview-skill.json` within each package. Scripts, executable files, undeclared files, and requested permissions fail checks and owner admission. There is no fixed release calendar: maintained packages are versioned when their content or compatibility changes. A breaking owner contract requires a new compatible maintained release before the product depends on it. ## A named set in RelayView diff --git a/packages/planner-scope/SKILL.md b/packages/planner-scope/SKILL.md index a47cc62..028dc09 100644 --- a/packages/planner-scope/SKILL.md +++ b/packages/planner-scope/SKILL.md @@ -3,7 +3,7 @@ name: planner-scope description: Check assigned issue scope, neighboring work, and verification before drafting a Plan. metadata: relayview-display-name: Planner scope - relayview-version: 0.8.0 + relayview-version: 0.8.1 --- # Planner scope diff --git a/packages/planner-scope/relayview-skill.json b/packages/planner-scope/relayview-skill.json index 035261d..fa8ce71 100644 --- a/packages/planner-scope/relayview-skill.json +++ b/packages/planner-scope/relayview-skill.json @@ -2,7 +2,7 @@ "schemaVersion": 2, "source": { "kind": "first-party", - "reference": "v0.8.0" + "reference": "v0.8.1" }, "role": "planner", "step": "planning", @@ -12,7 +12,7 @@ "files": [ { "path": "SKILL.md", - "sha256": "7dbd2ace7472a75c69b70ea118333429dfc7d56e5374454724805aa783cc0112" + "sha256": "94119fd02a634007f44c227e523802d8f8a7249a97a5526b888d8739401645a2" }, { "path": "scope.md", diff --git a/tests/test_packages.py b/tests/test_packages.py index f5edb31..3be04d6 100644 --- a/tests/test_packages.py +++ b/tests/test_packages.py @@ -12,6 +12,28 @@ ROOT = Path(__file__).resolve().parents[1] class PackageTests(unittest.TestCase): + def test_schema_two_claim_policy_bounds(self): + with tempfile.TemporaryDirectory() as directory: + package = Path(directory) / "planner-scope" + shutil.copytree(ROOT / "packages/planner-scope", package) + sidecar = package / "relayview-skill.json" + original = json.loads(sidecar.read_text()) + for label in (None, "status/review"): + manifest = dict(original, issueClaim={"statusLabel": label}) + sidecar.write_text(json.dumps(manifest)) + check_package(package) + for claim in ({}, [], {"statusLabel": "status/ready-for-agent"}, + {"statusLabel": 42}, {"statusLabel": "review"}, + {"statusLabel": None, "extra": True}): + with self.subTest(claim=claim): + sidecar.write_text(json.dumps(dict(original, issueClaim=claim))) + with self.assertRaises(PackageError): + check_package(package) + for role, step in (("implementer", "implementation"), ("reviewer", "review"), ("designer", "design")): + sidecar.write_text(json.dumps(dict(original, role=role, step=step))) + with self.assertRaises(PackageError): + check_package(package) + def test_planner_scope_presentation_and_claim(self): package = ROOT / "packages/planner-scope" check_package(package) @@ -113,7 +135,7 @@ class PackageTests(unittest.TestCase): package = ROOT / "packages" / name manifest = json.loads((package / "relayview-skill.json").read_text()) self.assertEqual((manifest["role"], manifest["step"]), (role, step)) - self.assertEqual(manifest["source"], {"kind": "first-party", "reference": "v0.8.0" if name == "planner-scope" else "v0.2.0"}) + self.assertEqual(manifest["source"], {"kind": "first-party", "reference": "v0.8.1" if name == "planner-scope" else "v0.2.0"}) self.assertIn(resource, [item["path"] for item in manifest["files"]]) self.assertIn(marker, (package / "SKILL.md").read_text() + (package / resource).read_text())