create-pmos 0.43.0 → 0.44.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/bin/cockpit-install.js +130 -0
- package/bin/create-pmos.js +47 -4
- package/package.json +1 -1
- package/payload/AGENTS-HUMAN.md +10 -25
- package/payload/AGENTS.md +4 -0
- package/payload/KIT-VERSION +1 -1
- package/payload/mods/.claude-plugin/marketplace.json +12 -0
- package/payload/mods/pmos-cockpit/.claude-plugin/plugin.json +9 -0
- package/payload/mods/pmos-cockpit/README.md +60 -0
- package/payload/mods/pmos-cockpit/hooks/hooks.json +1 -0
- package/payload/mods/pmos-cockpit/hooks/lib/commands.mjs +53 -0
- package/payload/mods/pmos-cockpit/hooks/lib/grants.mjs +88 -0
- package/payload/mods/pmos-cockpit/hooks/lib/guard.mjs +561 -0
- package/payload/mods/pmos-cockpit/hooks/lib/initiative.mjs +54 -0
- package/payload/mods/pmos-cockpit/hooks/lib/layout.mjs +31 -0
- package/payload/mods/pmos-cockpit/hooks/lib/profile.mjs +17 -0
- package/payload/mods/pmos-cockpit/hooks/lib/skills.mjs +69 -0
- package/payload/mods/pmos-cockpit/hooks/register.tsx +460 -0
- package/payload/mods/pmos-cockpit/types/index.d.ts +34 -0
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/scripts/pmos-log.sh +119 -7
- package/payload/skills/pmos-router.skill +1 -1
- package/payload/skills/prototype.skill +1 -1
- package/payload/skills/strategic-brief.skill +1 -1
- package/payload/skills-native/harness-refine/SKILL.md +1 -1
- package/payload/skills-native/pmos-router/SKILL.md +1 -1
- package/payload/skills-native/prototype/SKILL.md +1 -1
- package/payload/skills-native/strategic-brief/SKILL.md +1 -1
- package/payload/state/discoveries.md +1 -1
- package/workspace/package-lock.json +1 -1
- package/workspace/package.json +1 -1
|
@@ -3,18 +3,29 @@
|
|
|
3
3
|
# Appends ONE validated JSON line to the right pmos/state/ file. Mirrors the hosted rules:
|
|
4
4
|
# verdict enum (save_eval), pm_label enum (record_acceptance), disposition enum + the D57
|
|
5
5
|
# evidence-required-for-terminal rule (record_outcome_check). Append-only by construction — this
|
|
6
|
-
# script only ever
|
|
6
|
+
# script only ever appends; a correction is a NEW record. Parity with PMOS's own writers
|
|
7
|
+
# (pmos-cockpit-mod, D81): an acceptance needs a note and a run that exists, and a ledger that is a
|
|
8
|
+
# symlink or has another hard link is refused (the same rule as scripts/lib/sink.js, applied at the
|
|
9
|
+
# moment of the write; it does not defend against a process racing the open). No dependencies beyond POSIX + python3
|
|
7
10
|
# (used solely for safe JSON string escaping).
|
|
8
11
|
#
|
|
9
12
|
# pmos-log.sh run <run_id> <initiative_id> [human_corrections] [model]
|
|
10
13
|
# pmos-log.sh eval <run_id> <initiative_id> <score 0..1> <PASS|PASS-WITH-FINDINGS|FAIL> <rubric_path> [evaluator_model]
|
|
11
|
-
# pmos-log.sh accept <run_id> <initiative_id> <pass|fail>
|
|
14
|
+
# pmos-log.sh accept <run_id> <initiative_id> <pass|fail> <note>
|
|
12
15
|
# pmos-log.sh outcome <initiative_id> <validated|refuted|inconclusive> [evidence]
|
|
13
16
|
# pmos-log.sh friction <note...>
|
|
17
|
+
# pmos-log.sh grant <merge:<PR or branch>|publish:<artifact>> <pm> <instruction> [ttl_minutes]
|
|
18
|
+
# pmos-log.sh grant-use <grant_id> <action>
|
|
19
|
+
#
|
|
20
|
+
# `grant` and `grant-use` belong to the cockpit mod (D81). A grant is the PM's typed permission for
|
|
21
|
+
# ONE action: single use, 120 minutes unless a shorter time is given (24 hours at most), one target. A
|
|
22
|
+
# standing scope (docs-sync, outward:*) and any other scope is refused. The mod mints a grant only from
|
|
23
|
+
# the PM's typed /pmos-grant or a press, and denies a model that runs either subcommand.
|
|
24
|
+
# PMOS_STATE_DIR names the folder of the ledgers when it is not <kit>/state (PMOS's own repository).
|
|
14
25
|
set -euo pipefail
|
|
15
26
|
|
|
16
27
|
KIT="${KIT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
17
|
-
STATE="$KIT/state"
|
|
28
|
+
STATE="${PMOS_STATE_DIR:-$KIT/state}"
|
|
18
29
|
fail() { echo "pmos-log: ERROR — $*" >&2; exit 1; }
|
|
19
30
|
[ -d "$STATE" ] || fail "state dir not found at $STATE (run from a vendored kit, or set KIT_ROOT)."
|
|
20
31
|
|
|
@@ -24,8 +35,54 @@ nonempty() { # nonempty <label> <value> — ids must not be blank (hosted tools
|
|
|
24
35
|
}
|
|
25
36
|
today="$(date -u +%Y-%m-%d)"
|
|
26
37
|
|
|
38
|
+
# safe_append <file under state/> <line> — open with O_NOFOLLOW, then refuse anything that is not a
|
|
39
|
+
# regular file with a single link, and write to the descriptor that was vetted (python3 is already a
|
|
40
|
+
# dependency of this script). Nothing is written when it refuses.
|
|
41
|
+
safe_append() {
|
|
42
|
+
python3 - "$STATE/$1" "$2" <<'PY' || exit 1
|
|
43
|
+
import os, stat, sys
|
|
44
|
+
path, line = sys.argv[1], sys.argv[2]
|
|
45
|
+
flags = os.O_WRONLY | os.O_APPEND | os.O_CREAT | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_NONBLOCK", 0)
|
|
46
|
+
try:
|
|
47
|
+
fd = os.open(path, flags, 0o644)
|
|
48
|
+
except OSError as e:
|
|
49
|
+
sys.stderr.write("pmos-log: ERROR — refusing to write %s: %s\n" % (path, e.strerror)); sys.exit(1)
|
|
50
|
+
try:
|
|
51
|
+
st = os.fstat(fd)
|
|
52
|
+
if not stat.S_ISREG(st.st_mode) or st.st_nlink != 1:
|
|
53
|
+
sys.stderr.write("pmos-log: ERROR — refusing to write %s: it is not a regular file with a single link (a symlink, a hard link or a special file).\n" % path); sys.exit(1)
|
|
54
|
+
os.write(fd, (line + "\n").encode("utf-8"))
|
|
55
|
+
finally:
|
|
56
|
+
os.close(fd)
|
|
57
|
+
PY
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# run_exists <run_id> — true when state/runs.jsonl holds a run with that id. Lines that are not JSON
|
|
61
|
+
# are skipped; the checkers report them.
|
|
62
|
+
run_exists() {
|
|
63
|
+
python3 - "$STATE/runs.jsonl" "$1" <<'PY'
|
|
64
|
+
import json, sys
|
|
65
|
+
path, rid = sys.argv[1], sys.argv[2]
|
|
66
|
+
try:
|
|
67
|
+
lines = open(path, encoding="utf-8").read().splitlines()
|
|
68
|
+
except OSError:
|
|
69
|
+
sys.exit(1)
|
|
70
|
+
for l in lines:
|
|
71
|
+
l = l.strip()
|
|
72
|
+
if not l:
|
|
73
|
+
continue
|
|
74
|
+
try:
|
|
75
|
+
r = json.loads(l)
|
|
76
|
+
except ValueError:
|
|
77
|
+
continue
|
|
78
|
+
if isinstance(r, dict) and str(r.get("run_id", "")) == rid:
|
|
79
|
+
sys.exit(0)
|
|
80
|
+
sys.exit(1)
|
|
81
|
+
PY
|
|
82
|
+
}
|
|
83
|
+
|
|
27
84
|
append() { # append <file> <json-line>
|
|
28
|
-
|
|
85
|
+
safe_append "$1" "$2"
|
|
29
86
|
echo "✅ appended to state/$1:"
|
|
30
87
|
echo " $2"
|
|
31
88
|
}
|
|
@@ -86,9 +143,11 @@ case "$cmd" in
|
|
|
86
143
|
append evals.jsonl "{\"run_id\":$(js "$1"),\"initiative_id\":$(js "$2"),\"score\":$score,\"verdict\":$(js "$4"),\"rubric_path\":$(js "$5"),\"date\":\"$today\"$emodel_field}"
|
|
87
144
|
;;
|
|
88
145
|
accept)
|
|
89
|
-
[ $# -ge
|
|
146
|
+
[ $# -ge 4 ] || fail "usage: accept <run_id> <initiative_id> <pass|fail> <note> — the note is required: an acceptance with no reasoning is the rubber stamp D12 exists to prevent."
|
|
90
147
|
nonempty run_id "$1"; nonempty initiative_id "$2"
|
|
91
148
|
case "$3" in pass|fail) ;; *) fail "pm_label must be pass | fail, got '$3'." ;; esac
|
|
149
|
+
nonempty note "$4"
|
|
150
|
+
run_exists "$1" || fail "run_id '$1' is not in state/runs.jsonl — log the run first (pmos-log.sh run ...), then accept it."
|
|
92
151
|
acc=true; [ "$3" = fail ] && acc=false
|
|
93
152
|
append acceptances.jsonl "{\"run_id\":$(js "$1"),\"initiative_id\":$(js "$2"),\"accepted\":$acc,\"pm_label\":$(js "$3"),\"note\":$(js "${4:-}"),\"date\":\"$today\"}"
|
|
94
153
|
;;
|
|
@@ -104,10 +163,63 @@ case "$cmd" in
|
|
|
104
163
|
;;
|
|
105
164
|
friction)
|
|
106
165
|
[ $# -ge 1 ] || fail "usage: friction <note...>"
|
|
107
|
-
|
|
166
|
+
safe_append discoveries.md "- $today $* #friction"
|
|
108
167
|
echo "✅ appended to state/discoveries.md: - $today $* #friction"
|
|
109
168
|
;;
|
|
169
|
+
grant)
|
|
170
|
+
[ $# -ge 3 ] || fail "usage: grant <merge:<PR or branch>|publish:<artifact>> <pm> <instruction> [ttl_minutes]"
|
|
171
|
+
nonempty pm "$2"; nonempty instruction "$3"
|
|
172
|
+
row="$(python3 - "$1" "$2" "$3" "${4:-120}" <<'PY'
|
|
173
|
+
import datetime, json, re, secrets, sys
|
|
174
|
+
scope, pm, instruction, ttl = sys.argv[1:5]
|
|
175
|
+
def die(m):
|
|
176
|
+
sys.stderr.write("pmos-log: ERROR — %s\n" % m); sys.exit(1)
|
|
177
|
+
if re.match(r"^(docs-sync|outward)(:|$)", scope):
|
|
178
|
+
die('"%s" is a standing scope. Standing grants are not allowed in this release (D81). Mint one single-use grant per action.' % scope)
|
|
179
|
+
kind, sep, target = scope.partition(":")
|
|
180
|
+
if not sep or kind not in ("merge", "publish"):
|
|
181
|
+
die('unknown scope "%s". Use merge:<PR number or branch> or publish:<artifact>.' % scope)
|
|
182
|
+
pat = r"^(?:[0-9]{1,9}|[A-Za-z0-9][A-Za-z0-9._/-]{0,79})$" if kind == "merge" else r"^[A-Za-z0-9@][A-Za-z0-9@._/-]{0,99}$"
|
|
183
|
+
if not re.match(pat, target) or "*" in target or ".." in target:
|
|
184
|
+
die('"%s" is not a single %s. A grant names one target; a wildcard is refused.' % (target, "PR number or branch name" if kind == "merge" else "artifact name"))
|
|
185
|
+
if not re.match(r"^[0-9]{1,4}$", ttl) or not (1 <= int(ttl) <= 1440):
|
|
186
|
+
die("ttl_minutes must be a whole number from 1 to 1440, got '%s'." % ttl)
|
|
187
|
+
now = datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0)
|
|
188
|
+
fmt = lambda d: d.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
189
|
+
print(json.dumps({"type": "grant", "id": "g-%d-%s" % (int(now.timestamp()), secrets.token_hex(3)), "scope": kind, "target": target,
|
|
190
|
+
"pm": pm, "at": fmt(now), "expires_at": fmt(now + datetime.timedelta(minutes=int(ttl))), "uses": 1, "instruction": instruction}, separators=(",", ":")))
|
|
191
|
+
PY
|
|
192
|
+
)" || exit 1
|
|
193
|
+
append grants.jsonl "$row"
|
|
194
|
+
;;
|
|
195
|
+
grant-use)
|
|
196
|
+
[ $# -ge 2 ] || fail "usage: grant-use <grant_id> <action>"
|
|
197
|
+
nonempty grant_id "$1"; nonempty action "$2"
|
|
198
|
+
python3 - "$STATE/grants.jsonl" "$1" <<'PY' || exit 1
|
|
199
|
+
import json, sys
|
|
200
|
+
path, gid = sys.argv[1], sys.argv[2]
|
|
201
|
+
found = used = False
|
|
202
|
+
try:
|
|
203
|
+
lines = open(path, encoding="utf-8").read().splitlines()
|
|
204
|
+
except OSError:
|
|
205
|
+
lines = []
|
|
206
|
+
for l in lines:
|
|
207
|
+
try:
|
|
208
|
+
r = json.loads(l)
|
|
209
|
+
except ValueError:
|
|
210
|
+
continue
|
|
211
|
+
if isinstance(r, dict) and r.get("type") == "grant" and r.get("id") == gid:
|
|
212
|
+
found = True
|
|
213
|
+
if isinstance(r, dict) and r.get("type") == "use" and r.get("grant_id") == gid:
|
|
214
|
+
used = True
|
|
215
|
+
if not found:
|
|
216
|
+
sys.stderr.write("pmos-log: ERROR — grant_id '%s' is not in state/grants.jsonl.\n" % gid); sys.exit(1)
|
|
217
|
+
if used:
|
|
218
|
+
sys.stderr.write("pmos-log: ERROR — grant '%s' was already used. A grant is single use.\n" % gid); sys.exit(1)
|
|
219
|
+
PY
|
|
220
|
+
append grants.jsonl "{\"type\":\"use\",\"grant_id\":$(js "$1"),\"at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"action\":$(js "$2")}"
|
|
221
|
+
;;
|
|
110
222
|
*)
|
|
111
|
-
fail "unknown command '${cmd:-}' — one of: run | eval | accept | outcome | friction (see AGENTS-HUMAN.md)."
|
|
223
|
+
fail "unknown command '${cmd:-}' — one of: run | eval | accept | outcome | friction | grant | grant-use (see AGENTS-HUMAN.md)."
|
|
112
224
|
;;
|
|
113
225
|
esac
|
|
@@ -26,7 +26,7 @@ router is the bug (fix it via the weekly harness scan).
|
|
|
26
26
|
1. **Sharpness (the fog/ticket test):** *can the PM state the question or idea precisely now — not
|
|
27
27
|
answer it, state it?* If not, it is **fog**: not ready for intake. Name what would sharpen it
|
|
28
28
|
(a conversation, a datum, a spike) and stop — do not open an initiative to hold fog.
|
|
29
|
-
2. **Prior rejection:** check [planning/out-of-scope/](/README.md) for the
|
|
29
|
+
2. **Prior rejection:** check [planning/out-of-scope/](/planning/out-of-scope/README.md) for the
|
|
30
30
|
concept. If a file exists, **read it first** and surface it to the PM — the concept returns only
|
|
31
31
|
if the PM overrides the recorded reasoning, and the file is updated either way.
|
|
32
32
|
3. **The specimen test — ASK it, do not wait to be told** (D60 as amended 2026-07-24):
|
|
@@ -131,7 +131,7 @@ system, a convention set, or a prototype to validate an idea.
|
|
|
131
131
|
work has a surface, then runs inside that initiative's Build.
|
|
132
132
|
- **iterate** → back to step 5 with the PM's reaction folded in.
|
|
133
133
|
- **kill** → record one honest line on the initiative, **file the concept into
|
|
134
|
-
[planning/out-of-scope/](/README.md)** (decision, reasoning, what would
|
|
134
|
+
[planning/out-of-scope/](/planning/out-of-scope/README.md)** (decision, reasoning, what would
|
|
135
135
|
reopen it) so it is not re-prototyped from scratch, and close. A cheap kill is this lane
|
|
136
136
|
*succeeding*.
|
|
137
137
|
8. **Log.** `log_agent_run` with the disposition; friction to discoveries.md (`#friction`).
|
|
@@ -49,7 +49,7 @@ volume where informal prioritization strains) are now met.
|
|
|
49
49
|
|
|
50
50
|
- `planning/briefs/<initiative-id>-brief.md` — operational instance, never in the OKF bundle.
|
|
51
51
|
- An accepted brief becomes the PRD's parent rationale (the PRD links it). A **no-go** files the
|
|
52
|
-
concept into [planning/out-of-scope/](/README.md) so it is not re-litigated.
|
|
52
|
+
concept into [planning/out-of-scope/](/planning/out-of-scope/README.md) so it is not re-litigated.
|
|
53
53
|
|
|
54
54
|
## Level 3 sub-cases
|
|
55
55
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: harness-refine
|
|
3
|
-
description:
|
|
3
|
+
description: "Turn PMOS's own run evidence into concrete, evidence-cited edits to the harness. Read the eval defects, recurring friction, run transcripts, and the calibration log; cluster them into specific proposed edits \u2014 each mapped to ONE artifact (an MCP tool description, a skill body, an OKF concept, or an AGENTS.md heuristic) and citing the run/friction/eval that motivates it \u2014 including prunes of scaffolding the model now handles natively. Emit a proposals report and open a PR for the PM. Use on demand: when the PM invokes it, at the D23 quarterly harness review, or when v_friction_recurrence / recurring eval defects show a harness gap. Never merges, never self-approves, never auto-applies."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
pmos-maturity_mode: active
|
|
@@ -28,7 +28,7 @@ router is the bug (fix it via the weekly harness scan).
|
|
|
28
28
|
1. **Sharpness (the fog/ticket test):** *can the PM state the question or idea precisely now — not
|
|
29
29
|
answer it, state it?* If not, it is **fog**: not ready for intake. Name what would sharpen it
|
|
30
30
|
(a conversation, a datum, a spike) and stop — do not open an initiative to hold fog.
|
|
31
|
-
2. **Prior rejection:** check [planning/out-of-scope/](/README.md) for the
|
|
31
|
+
2. **Prior rejection:** check [planning/out-of-scope/](/planning/out-of-scope/README.md) for the
|
|
32
32
|
concept. If a file exists, **read it first** and surface it to the PM — the concept returns only
|
|
33
33
|
if the PM overrides the recorded reasoning, and the file is updated either way.
|
|
34
34
|
3. **The specimen test — ASK it, do not wait to be told** (D60 as amended 2026-07-24):
|
|
@@ -133,7 +133,7 @@ system, a convention set, or a prototype to validate an idea.
|
|
|
133
133
|
work has a surface, then runs inside that initiative's Build.
|
|
134
134
|
- **iterate** → back to step 5 with the PM's reaction folded in.
|
|
135
135
|
- **kill** → record one honest line on the initiative, **file the concept into
|
|
136
|
-
[planning/out-of-scope/](/README.md)** (decision, reasoning, what would
|
|
136
|
+
[planning/out-of-scope/](/planning/out-of-scope/README.md)** (decision, reasoning, what would
|
|
137
137
|
reopen it) so it is not re-prototyped from scratch, and close. A cheap kill is this lane
|
|
138
138
|
*succeeding*.
|
|
139
139
|
8. **Log.** `log_agent_run` with the disposition; friction to discoveries.md (`#friction`).
|
|
@@ -51,7 +51,7 @@ volume where informal prioritization strains) are now met.
|
|
|
51
51
|
|
|
52
52
|
- `planning/briefs/<initiative-id>-brief.md` — operational instance, never in the OKF bundle.
|
|
53
53
|
- An accepted brief becomes the PRD's parent rationale (the PRD links it). A **no-go** files the
|
|
54
|
-
concept into [planning/out-of-scope/](/README.md) so it is not re-litigated.
|
|
54
|
+
concept into [planning/out-of-scope/](/planning/out-of-scope/README.md) so it is not re-litigated.
|
|
55
55
|
|
|
56
56
|
## Level 3 sub-cases
|
|
57
57
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type: Reference
|
|
3
3
|
title: "Discoveries and friction log"
|
|
4
4
|
description: "Append-only record of what runs discovered and where the process rubbed."
|
|
5
|
-
generated: {by: process:create-pmos, at: "2026-10-
|
|
5
|
+
generated: {by: process:create-pmos, at: "2026-10-04T08:22:32Z"}
|
|
6
6
|
status: stable
|
|
7
7
|
---
|
|
8
8
|
|
package/workspace/package.json
CHANGED