@gillcash/necktie 0.2.0
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.
- package/.opencode/command/necktie-critique.md +5 -0
- package/.opencode/command/necktie-reverse.md +5 -0
- package/.opencode/command/necktie-review.md +5 -0
- package/.opencode/command/necktie.md +5 -0
- package/.opencode/plugins/necktie-frontmatter.cjs +12 -0
- package/.opencode/plugins/necktie.mjs +35 -0
- package/.qoder/rules/necktie.md +18 -0
- package/.qoder-plugin/plugin.json +13 -0
- package/AGENTS.md +18 -0
- package/LICENSE +22 -0
- package/NOTICE +7 -0
- package/README.es.md +84 -0
- package/README.ko.md +84 -0
- package/README.md +232 -0
- package/assets/logo-dark.png +0 -0
- package/assets/necktie-icon-pack-preview.png +0 -0
- package/commands/necktie-critique.toml +2 -0
- package/commands/necktie-reverse.toml +2 -0
- package/commands/necktie-review.toml +2 -0
- package/commands/necktie.toml +2 -0
- package/core/necktie-core.md +18 -0
- package/hooks/copilot-hooks.json +13 -0
- package/hooks/hooks.json +27 -0
- package/hooks/necktie-context.js +43 -0
- package/hooks/qoder-hooks.json +26 -0
- package/package.json +55 -0
- package/pi-extension/index.js +29 -0
- package/pi-extension/package.json +9 -0
- package/plugin.json +14 -0
- package/skills/necktie/SKILL.md +95 -0
- package/skills/necktie/agents/openai.yaml +6 -0
- package/skills/necktie/references/loop-protocol.md +85 -0
- package/skills/necktie/scripts/necktie_loop.py +199 -0
- package/skills/necktie-critique/SKILL.md +48 -0
- package/skills/necktie-critique/agents/openai.yaml +6 -0
- package/skills/necktie-reverse/SKILL.md +41 -0
- package/skills/necktie-reverse/agents/openai.yaml +6 -0
- package/skills/necktie-reverse/references/blueprint-template.md +54 -0
- package/skills/necktie-review/SKILL.md +61 -0
- package/skills/necktie-review/agents/openai.yaml +6 -0
- package/skills/necktie-review/references/reviewer-rubric.md +29 -0
- package/skills/necktie-review/scripts/validate_review.py +110 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Executable brief template
|
|
2
|
+
|
|
3
|
+
Use these headings. Omit a heading only when it is genuinely inapplicable.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
ROLE
|
|
7
|
+
Act as [relevant role and perspective].
|
|
8
|
+
|
|
9
|
+
OUTCOME
|
|
10
|
+
Produce [artifact/action] so that [audience] can [real-world outcome].
|
|
11
|
+
|
|
12
|
+
INPUTS AND SOURCE HIERARCHY
|
|
13
|
+
- Evidence: [sources that may support claims]
|
|
14
|
+
- Method guidance: [sources that govern the process only]
|
|
15
|
+
- Constraints: [authority, safety, scope, format]
|
|
16
|
+
- Prior outputs: [hypotheses/style references only]
|
|
17
|
+
Resolve conflicts in this order: [explicit hierarchy].
|
|
18
|
+
|
|
19
|
+
SCOPE
|
|
20
|
+
Include: [...]
|
|
21
|
+
Exclude: [...]
|
|
22
|
+
|
|
23
|
+
MATERIAL ASSUMPTIONS
|
|
24
|
+
- [...]
|
|
25
|
+
|
|
26
|
+
WORKFLOW
|
|
27
|
+
1. Inspect and classify sources.
|
|
28
|
+
2. Establish a baseline and expose assumptions.
|
|
29
|
+
3. Challenge the inquiry and identify the strongest unasked question.
|
|
30
|
+
4. Produce the deliverable from raw evidence.
|
|
31
|
+
5. Review against the acceptance criteria.
|
|
32
|
+
6. Revise within the stated stopping rule.
|
|
33
|
+
7. Verify in the target environment.
|
|
34
|
+
|
|
35
|
+
DELIVERABLES
|
|
36
|
+
- [exact output, format, and location]
|
|
37
|
+
|
|
38
|
+
ACCEPTANCE CRITERIA
|
|
39
|
+
- [observable pass/fail criterion]
|
|
40
|
+
|
|
41
|
+
EVIDENCE AND CITATION RULES
|
|
42
|
+
- [claim support, freshness, provenance, quotation, or uncertainty rules]
|
|
43
|
+
|
|
44
|
+
REVIEW CONTRACT
|
|
45
|
+
Return APPROVE, REVISE, or BLOCK. Report only material findings with exact evidence and the smallest required change. Ask the strongest unasked expert question. Do not rewrite while reviewing.
|
|
46
|
+
|
|
47
|
+
STOPPING RULE
|
|
48
|
+
Stop when all criteria pass, a material blocker requires user input, the same issue survives three reviews, or three revision decisions are recorded.
|
|
49
|
+
|
|
50
|
+
HANDOFF
|
|
51
|
+
Return the artifact, reusable brief, verification record, limitations, overlooked consideration, and strongest unasked question.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Write instructions that are observable and testable. Replace adjectives such as "excellent" or "comprehensive" with explicit criteria. Do not request hidden chain-of-thought; request concise assumptions, decisions, evidence, and verification instead.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: necktie-review
|
|
3
|
+
description: Independently gate a candidate deliverable against its exact brief, evidence, acceptance criteria, and verification results. Use inside the Necktie loop, for an Auto-review-style approval decision, or when the user wants a concise APPROVE, REVISE, or BLOCK judgment with actionable material findings and a strongest unasked question.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Necktie Review
|
|
7
|
+
|
|
8
|
+
Judge the proposed result without silently rewriting it or expanding its scope. Review as a separate role from the author, using the smallest evidence packet that permits a reliable decision.
|
|
9
|
+
|
|
10
|
+
## Inputs
|
|
11
|
+
|
|
12
|
+
Require:
|
|
13
|
+
|
|
14
|
+
- the exact executable brief;
|
|
15
|
+
- the candidate artifact or change set;
|
|
16
|
+
- acceptance criteria and constraints;
|
|
17
|
+
- a source ledger plus relevant evidence excerpts, paths, or links;
|
|
18
|
+
- verification results, if already available.
|
|
19
|
+
|
|
20
|
+
If an input is unavailable, decide whether that absence is itself a material finding. Read [references/reviewer-rubric.md](references/reviewer-rubric.md) completely before judging.
|
|
21
|
+
|
|
22
|
+
## Review
|
|
23
|
+
|
|
24
|
+
1. Inspect the candidate read-only. Do not author fixes while acting as reviewer.
|
|
25
|
+
2. Test each acceptance criterion and every material factual claim against the evidence ledger.
|
|
26
|
+
3. Look for omissions, contradictions, fabricated support, stale assumptions, unsafe actions, unusable formatting, and failure to verify in the target environment.
|
|
27
|
+
4. Check whether the deliverable advances the actual goal rather than merely matching its requested shape.
|
|
28
|
+
5. Identify what the author and user may not have considered.
|
|
29
|
+
6. Name the single strongest unasked expert question and its consequence.
|
|
30
|
+
7. Report only material findings. Combine duplicates and point to exact locations when possible.
|
|
31
|
+
|
|
32
|
+
## Decide
|
|
33
|
+
|
|
34
|
+
- `APPROVE`: no critical or major finding remains. Minor optional improvements may be noted but cannot block approval.
|
|
35
|
+
- `REVISE`: one or more fixable critical or major findings remain. State the smallest required change for each.
|
|
36
|
+
- `BLOCK`: a required decision, authority, source, or safe execution path is absent and the author cannot resolve it within scope.
|
|
37
|
+
|
|
38
|
+
Confidence is not a substitute for evidence. Do not approve because the prose sounds plausible.
|
|
39
|
+
|
|
40
|
+
## Output
|
|
41
|
+
|
|
42
|
+
Return only one JSON object matching this shape:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"decision": "APPROVE",
|
|
47
|
+
"summary": "One-sentence basis for the decision.",
|
|
48
|
+
"findings": [],
|
|
49
|
+
"strongest_unasked_question": "The highest-leverage omitted question.",
|
|
50
|
+
"question_consequence": "What changes if its answer differs.",
|
|
51
|
+
"confidence": "high"
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Each finding must contain `id`, `severity` (`critical`, `major`, or `minor`), `criterion`, `location`, `evidence`, and `required_change`. Use an empty findings array only for approval. Validate a saved decision with:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
python skills/necktie-review/scripts/validate_review.py review.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Do not include markdown around the JSON, private reasoning, or an edited artifact.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Necktie reviewer rubric
|
|
2
|
+
|
|
3
|
+
## Order of review
|
|
4
|
+
|
|
5
|
+
1. **Authority and safety**: Is the action permitted, reversible where appropriate, and within the agreed scope?
|
|
6
|
+
2. **Goal fit**: Does the artifact support the user's actual outcome and audience?
|
|
7
|
+
3. **Evidence integrity**: Are material claims traceable to eligible, current sources? Are method context and prior outputs kept out of the evidence chain?
|
|
8
|
+
4. **Correctness and completeness**: Are calculations, logic, content, and required sections accurate and sufficient?
|
|
9
|
+
5. **Usability**: Can the intended audience use the result in its target environment?
|
|
10
|
+
6. **Verification**: Were the relevant tests, renders, checks, or inspections performed, and do their results support completion?
|
|
11
|
+
7. **Economy**: Is the solution no larger or more complex than the goal requires?
|
|
12
|
+
|
|
13
|
+
## Severity
|
|
14
|
+
|
|
15
|
+
- `critical`: could cause unsafe action, material loss, invalid conclusion, unauthorized change, or failure of the central deliverable.
|
|
16
|
+
- `major`: violates an acceptance criterion, leaves a material unsupported claim, omits a necessary component, or prevents intended use.
|
|
17
|
+
- `minor`: real but non-blocking defect that does not change the decision or intended use.
|
|
18
|
+
|
|
19
|
+
Do not inflate preferences into findings. A valid finding states the violated criterion, exact location, concrete evidence, and smallest required change.
|
|
20
|
+
|
|
21
|
+
## Decision examples
|
|
22
|
+
|
|
23
|
+
- Approve a sound artifact with an optional wording improvement; record it only as a minor finding if useful.
|
|
24
|
+
- Revise when a KPI definition lacks a denominator, a cited claim is unsupported, a requested file does not render, or a required test fails.
|
|
25
|
+
- Block when the user must choose between materially different scopes, required private data is unavailable, or execution needs authority the run does not possess.
|
|
26
|
+
|
|
27
|
+
## Independence
|
|
28
|
+
|
|
29
|
+
Review the artifact that exists, not the artifact you imagine the author intended. Do not fix it during the review pass. If revising later, leave reviewer role and return to author role first.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate the JSON decision emitted by the Necktie reviewer skill."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
TOP_LEVEL_KEYS = {
|
|
13
|
+
"decision",
|
|
14
|
+
"summary",
|
|
15
|
+
"findings",
|
|
16
|
+
"strongest_unasked_question",
|
|
17
|
+
"question_consequence",
|
|
18
|
+
"confidence",
|
|
19
|
+
}
|
|
20
|
+
FINDING_KEYS = {"id", "severity", "criterion", "location", "evidence", "required_change"}
|
|
21
|
+
DECISIONS = {"APPROVE", "REVISE", "BLOCK"}
|
|
22
|
+
SEVERITIES = {"critical", "major", "minor"}
|
|
23
|
+
CONFIDENCE = {"high", "medium", "low"}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def nonempty_string(value: object) -> bool:
|
|
27
|
+
return isinstance(value, str) and bool(value.strip())
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def validate_review(value: object) -> list[str]:
|
|
31
|
+
errors: list[str] = []
|
|
32
|
+
if not isinstance(value, dict):
|
|
33
|
+
return ["review must be a JSON object"]
|
|
34
|
+
|
|
35
|
+
missing = sorted(TOP_LEVEL_KEYS - value.keys())
|
|
36
|
+
extra = sorted(value.keys() - TOP_LEVEL_KEYS)
|
|
37
|
+
if missing:
|
|
38
|
+
errors.append(f"missing top-level keys: {', '.join(missing)}")
|
|
39
|
+
if extra:
|
|
40
|
+
errors.append(f"unexpected top-level keys: {', '.join(extra)}")
|
|
41
|
+
if missing:
|
|
42
|
+
return errors
|
|
43
|
+
|
|
44
|
+
decision = value["decision"]
|
|
45
|
+
if decision not in DECISIONS:
|
|
46
|
+
errors.append(f"decision must be one of: {', '.join(sorted(DECISIONS))}")
|
|
47
|
+
for field in ("summary", "strongest_unasked_question", "question_consequence"):
|
|
48
|
+
if not nonempty_string(value[field]):
|
|
49
|
+
errors.append(f"{field} must be a non-empty string")
|
|
50
|
+
if value["confidence"] not in CONFIDENCE:
|
|
51
|
+
errors.append(f"confidence must be one of: {', '.join(sorted(CONFIDENCE))}")
|
|
52
|
+
|
|
53
|
+
findings = value["findings"]
|
|
54
|
+
if not isinstance(findings, list):
|
|
55
|
+
errors.append("findings must be an array")
|
|
56
|
+
return errors
|
|
57
|
+
|
|
58
|
+
blocking_findings = 0
|
|
59
|
+
seen_ids: set[str] = set()
|
|
60
|
+
for index, finding in enumerate(findings):
|
|
61
|
+
prefix = f"findings[{index}]"
|
|
62
|
+
if not isinstance(finding, dict):
|
|
63
|
+
errors.append(f"{prefix} must be an object")
|
|
64
|
+
continue
|
|
65
|
+
missing_finding = sorted(FINDING_KEYS - finding.keys())
|
|
66
|
+
extra_finding = sorted(finding.keys() - FINDING_KEYS)
|
|
67
|
+
if missing_finding:
|
|
68
|
+
errors.append(f"{prefix} missing keys: {', '.join(missing_finding)}")
|
|
69
|
+
if extra_finding:
|
|
70
|
+
errors.append(f"{prefix} unexpected keys: {', '.join(extra_finding)}")
|
|
71
|
+
if missing_finding:
|
|
72
|
+
continue
|
|
73
|
+
for field in FINDING_KEYS - {"severity"}:
|
|
74
|
+
if not nonempty_string(finding[field]):
|
|
75
|
+
errors.append(f"{prefix}.{field} must be a non-empty string")
|
|
76
|
+
if finding["severity"] not in SEVERITIES:
|
|
77
|
+
errors.append(f"{prefix}.severity must be one of: {', '.join(sorted(SEVERITIES))}")
|
|
78
|
+
elif finding["severity"] in {"critical", "major"}:
|
|
79
|
+
blocking_findings += 1
|
|
80
|
+
if finding["id"] in seen_ids:
|
|
81
|
+
errors.append(f"duplicate finding id: {finding['id']}")
|
|
82
|
+
seen_ids.add(finding["id"])
|
|
83
|
+
|
|
84
|
+
if decision == "APPROVE" and blocking_findings:
|
|
85
|
+
errors.append("APPROVE cannot contain critical or major findings")
|
|
86
|
+
if decision in {"REVISE", "BLOCK"} and blocking_findings == 0:
|
|
87
|
+
errors.append(f"{decision} requires at least one critical or major finding")
|
|
88
|
+
return errors
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def main(argv: list[str] | None = None) -> int:
|
|
92
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
93
|
+
parser.add_argument("review", type=Path)
|
|
94
|
+
args = parser.parse_args(argv)
|
|
95
|
+
try:
|
|
96
|
+
value = json.loads(args.review.read_text(encoding="utf-8"))
|
|
97
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
98
|
+
print(f"invalid: {exc}", file=sys.stderr)
|
|
99
|
+
return 2
|
|
100
|
+
errors = validate_review(value)
|
|
101
|
+
if errors:
|
|
102
|
+
for error in errors:
|
|
103
|
+
print(f"invalid: {error}", file=sys.stderr)
|
|
104
|
+
return 1
|
|
105
|
+
print("valid Necktie review")
|
|
106
|
+
return 0
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
if __name__ == "__main__":
|
|
110
|
+
raise SystemExit(main())
|