@chrono-meta/fh-gate 1.4.95 → 1.4.96
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/.claude-plugin/marketplace.json +2 -2
- package/AGENTS.md +18 -0
- package/CHEATSHEET.md +1 -1
- package/knowledge/shared/harness-core/fh_detail_protocols.md +12 -0
- package/knowledge/shared/harness-core/ship_readiness_gate.md +7 -4
- package/knowledge/shared/learnings/subagent_invocations_log.yaml +43 -1
- package/package.json +6 -1
- package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-commons/agents/quench-challenger.md +49 -23
- package/plugins/fh-commons/skills/convergence-loop/SKILL.md +14 -0
- package/plugins/fh-commons/skills/deliberation/SKILL.md +14 -0
- package/plugins/fh-commons/skills/mcp-circuit-breaker/SKILL.md +10 -1
- package/plugins/fh-meta/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-meta/CHANGELOG.md +36 -0
- package/plugins/fh-meta/agents/beginner.md +4 -1
- package/plugins/fh-meta/agents/challenger.md +7 -1
- package/plugins/fh-meta/agents/expert.md +1 -1
- package/plugins/fh-meta/agents/fact-checker.md +7 -1
- package/plugins/fh-meta/agents/hub-persona-auditor.md +2 -1
- package/plugins/fh-meta/agents/main-player.md +4 -1
- package/plugins/fh-meta/agents/persona-innovator.md +10 -2
- package/plugins/fh-meta/skills/agent-composer/SKILL.md +2 -2
- package/plugins/fh-meta/skills/apex-review/SKILL.md +5 -0
- package/plugins/fh-meta/skills/asset-placement-gate/SKILL.md +38 -8
- package/plugins/fh-meta/skills/auto-decorrelation/SKILL.md +16 -2
- package/plugins/fh-meta/skills/context-doctor/SKILL_detail.md +45 -10
- package/plugins/fh-meta/skills/corpus-grounding-expander/SKILL.md +14 -5
- package/plugins/fh-meta/skills/cross-ecosystem-synergy-detection/SKILL.md +93 -30
- package/plugins/fh-meta/skills/deep-clarify/SKILL.md +28 -9
- package/plugins/fh-meta/skills/fh/SKILL.md +4 -0
- package/plugins/fh-meta/skills/frontier-digest/SKILL.md +64 -8
- package/plugins/fh-meta/skills/frontier-digest/SKILL_detail.md +20 -7
- package/plugins/fh-meta/skills/goal-quench/SKILL.md +48 -15
- package/plugins/fh-meta/skills/goal-quench/SKILL_detail.md +58 -11
- package/plugins/fh-meta/skills/harness-doctor/SKILL_detail.md +109 -33
- package/plugins/fh-meta/skills/harvest-loop/SKILL.md +6 -1
- package/plugins/fh-meta/skills/hub-cc-pr-reviewer/SKILL.md +126 -17
- package/plugins/fh-meta/skills/install-doctor/SKILL.md +50 -14
- package/plugins/fh-meta/skills/install-wizard/SKILL.md +26 -7
- package/plugins/fh-meta/skills/install-wizard/SKILL_detail.md +68 -21
- package/plugins/fh-meta/skills/memory-hygiene/SKILL.md +64 -17
- package/plugins/fh-meta/skills/meta-prompt-builder/SKILL.md +38 -4
- package/plugins/fh-meta/skills/persona-roster-expander/SKILL.md +15 -7
- package/plugins/fh-meta/skills/plugin-recommender/SKILL.md +39 -11
- package/plugins/fh-meta/skills/plugin-recommender/SKILL_detail.md +24 -7
- package/plugins/fh-meta/skills/prompt-regression/SKILL.md +54 -11
- package/plugins/fh-meta/skills/salience-splitter/SKILL.md +120 -7
- package/plugins/fh-meta/skills/salience-splitter/SKILL_detail.md +46 -13
- package/plugins/fh-meta/skills/sim-conductor/SKILL_detail.md +28 -3
- package/plugins/fh-meta/skills/steel-quench/SKILL.md +3 -1
- package/plugins/fh-meta/skills/verify-bidirectional/SKILL.md +72 -14
- package/scripts/count_check.sh +47 -1
- package/scripts/degrade_direction_scan.sh +276 -6
- package/scripts/degrade_probe_capability.sh +105 -0
- package/scripts/package_coverage_check.sh +8 -0
- package/scripts/psa_probe_capability.sh +78 -0
- package/scripts/public_surface_scan_files.sh +8 -0
- package/scripts/selfcheck.sh +15 -0
- package/scripts/test_capability_entrypoint_shipping.sh +132 -0
- package/scripts/test_count_check_readme_format_lanes.sh +75 -0
- package/scripts/test_degrade_scan_shell_probes.sh +415 -0
- package/scripts/validate_yaml.sh +146 -0
- package/templates/degrade_direction_scan.sh +276 -6
|
@@ -69,7 +69,13 @@ Additional checklist for the human operator:
|
|
|
69
69
|
|
|
70
70
|
### 1-a. Load naming history
|
|
71
71
|
|
|
72
|
-
**Path A (hub environment with naming history)**:
|
|
72
|
+
**Path A (hub environment with naming history)**: read the naming history from `CATALOG.md` and
|
|
73
|
+
`knowledge/shared/` (both repo-root, both present). *Corrected 2026-08-11: this said `MEMORY.md`,
|
|
74
|
+
which does not exist at the repo root (`ls MEMORY.md` → No such file; control: `CATALOG.md` and
|
|
75
|
+
`README.md` resolve). Path A therefore read nothing and rendered as "no naming gap found" — and
|
|
76
|
+
Path B could not catch it, because its condition is "external environment" and this IS the hub.*
|
|
77
|
+
**If neither source resolves, degrade to Path B and say so in Section 0 — a silent empty read is
|
|
78
|
+
not a finding of zero.**
|
|
73
79
|
|
|
74
80
|
**Path B (external environment)**: Skip memory read. Use only the naming pattern taxonomy below (§ Naming pattern taxonomy) and the current invocation context.
|
|
75
81
|
|
|
@@ -77,7 +83,9 @@ Additional checklist for the human operator:
|
|
|
77
83
|
|
|
78
84
|
Scan current asset inventory using Grep/Glob:
|
|
79
85
|
```
|
|
80
|
-
|
|
86
|
+
Grep tool: pattern `candidate|gap|unnamed|no name`, path `.` (repo root)
|
|
87
|
+
— stated as a Grep-tool call, not a shell line: this agent declares `tools: Read, Grep, Glob`
|
|
88
|
+
and has no Bash, so a shell command here is an instruction it cannot execute.
|
|
81
89
|
```
|
|
82
90
|
|
|
83
91
|
Also look for:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: agent-composer
|
|
3
3
|
description: Reads the current work context and plans the optimal agent dispatch. Clarifies direction with 1-2 questions when unclear; infers and proceeds immediately when execution path is unclear. Runs an automatic recording gate after each Wave completes. Triggered by "compose agents", "which agent should I use?", "run in parallel", or "agent-composer".
|
|
4
4
|
user-invocable: true
|
|
5
|
-
allowed-tools: ["Read", "Bash", "Glob", "Grep"]
|
|
5
|
+
allowed-tools: ["Read", "Bash", "Glob", "Grep", "Agent", "Skill"]
|
|
6
6
|
model-note: session-inherit — Sonnet base is first-class (sonnet_floor_doctrine.md); depth-critical judged steps route to dispatch (opus agent / cross-family sidecar, consent-gated), never a substrate requirement
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -150,7 +150,7 @@ This orchestrator does not read files or understand structure directly — **eve
|
|
|
150
150
|
|
|
151
151
|
Default composition table by task type.
|
|
152
152
|
|
|
153
|
-
> **Note**: This table lists known installed agents. Capability fit scoring in Step 0.2 overrides static mapping when `agent_cards.json` has more current data.
|
|
153
|
+
> **Note**: This table lists known installed agents. Capability fit scoring in Step 0.2 overrides static mapping when `.claude/registry/agent_cards.json` (repo-relative — there is no bare `agent_cards.json` at the repo root) has more current data.
|
|
154
154
|
|
|
155
155
|
> **Call method distinction**: `(S)` = Skill tool call / `(A)` = Background dispatch via Agent tool
|
|
156
156
|
|
|
@@ -177,6 +177,11 @@ Incorporate sim-conductor results into the HTML deck and save the revised versio
|
|
|
177
177
|
All steps 0–4 completed
|
|
178
178
|
+ Verdict (✅/⚠️/❌) output for all target decision-makers
|
|
179
179
|
+ Gate verdict (Passed / Conditionally passed / Rejected) stated
|
|
180
|
+
+ Deck artifact exists on disk: `apex_review_deck_YYYYMMDD.html` (Step 2) — confirm by printing its
|
|
181
|
+
path and byte size; this is the skill's only durable output, so "reviewed but no deck" is NOT done
|
|
182
|
+
+ If the gate verdict is `Conditionally passed`: the `/sim-conductor Area E` verdict has been
|
|
183
|
+
RECEIVED and folded in (the mandatory-next gate below). Without that verdict the run is not done,
|
|
184
|
+
regardless of the A/B/C/D selection
|
|
180
185
|
+ User next step selection (A/B/C/D) confirmed
|
|
181
186
|
```
|
|
182
187
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: asset-placement-gate
|
|
3
3
|
description: Routes a proposed skill, plugin, or agent to its correct home — forge-harness (FH) meta-skill, project-local agent, or drop — by applying a 4-criteria meta-skill bar followed by a project-local value test.
|
|
4
4
|
user-invocable: true
|
|
5
|
-
allowed-tools: ["Read", "Grep", "Glob"]
|
|
5
|
+
allowed-tools: ["Read", "Grep", "Glob", "Bash"]
|
|
6
6
|
model: sonnet
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -73,19 +73,37 @@ Criterion ④ ("no overlap with existing FH skills") is otherwise an LLM **recal
|
|
|
73
73
|
ground truth — a duplicate skill with a novel name passes because the judge has no enumerated list to
|
|
74
74
|
check against (judge-robustness swarm, 2026-06-13). Ground it mechanically first:
|
|
75
75
|
|
|
76
|
+
Run this in **Bash** from the FH repo root (the pipeline below is `grep | grep -v | grep -c`, which the
|
|
77
|
+
Grep tool cannot express).
|
|
78
|
+
|
|
76
79
|
```bash
|
|
77
|
-
# enumerate existing skill names + descriptions (grounds the judged comparison)
|
|
78
|
-
|
|
79
|
-
#
|
|
80
|
+
# LEG A — enumerate existing skill names + descriptions (grounds the judged comparison).
|
|
81
|
+
# This leg is ALSO the liveness check for leg B: a dead scan and a genuine no-collision both
|
|
82
|
+
# produce collision-count 0, so the enumerate count must be read FIRST.
|
|
83
|
+
ROSTER="$(grep -riE 'name:|description:' plugins/fh-meta/skills/*/SKILL.md plugins/fh-commons/skills/*/SKILL.md)"
|
|
84
|
+
ROSTER_N="$(printf '%s' "$ROSTER" | grep -c . )"
|
|
85
|
+
echo "roster_entries=$ROSTER_N"
|
|
86
|
+
if [ "$ROSTER_N" -eq 0 ]; then
|
|
87
|
+
echo "SCAN_DEAD — enumerate leg returned 0 rows (wrong cwd / missing plugins tree / glob did not match)."
|
|
88
|
+
echo "Criterion ④ = UNDETERMINED. Do NOT read this as 'no collision'. Fix the cwd and re-run."
|
|
89
|
+
# fail-closed: stop here, do not run leg B, do not pass ④
|
|
90
|
+
fi
|
|
91
|
+
# LEG B — hard-collision check (run ONLY when ROSTER_N > 0).
|
|
92
|
+
# WHOLE proposed name or a WHOLE trigger phrase reused verbatim.
|
|
80
93
|
# grep -wF (whole-word, fixed-string) on the full strings — NOT -E on tokens (a shared common
|
|
81
94
|
# word like "review" is not a collision). Exclude the asset's own file (self-match = false hit).
|
|
82
|
-
SELF="plugins/fh-meta/skills
|
|
83
|
-
grep -rwF -e "
|
|
95
|
+
SELF="plugins/fh-meta/skills/PROPOSED_NAME/SKILL.md"
|
|
96
|
+
grep -rwF -e "PROPOSED_FULL_NAME" -e "FULL_TRIGGER_PHRASE_1" -e "FULL_TRIGGER_PHRASE_2" \
|
|
84
97
|
plugins/*/skills/*/SKILL.md | grep -v "$SELF" | grep -c .
|
|
85
98
|
```
|
|
86
99
|
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
(Replace the `PROPOSED_*` / `FULL_TRIGGER_*` tokens with the literal strings under evaluation.)
|
|
101
|
+
|
|
102
|
+
Surface **roster_entries + collision count + nearest existing skill(s)** — the roster count is part of
|
|
103
|
+
the report, not a private step: `collision=0` is only meaningful next to a non-zero `roster_entries`
|
|
104
|
+
(not-found ≠ zero). Criterion ④ then passes only if **`roster_entries` > 0 AND 0 whole-name/
|
|
105
|
+
whole-trigger collision AND the judged ≤90%-overlap check agrees**. `roster_entries = 0` is
|
|
106
|
+
`SCAN_DEAD` → ④ **UNDETERMINED** (fail-closed), never a pass. A verbatim whole-name or
|
|
89
107
|
whole-trigger reuse is a hard ④ fail regardless of the LLM judgment. **Honest scope**: the grep grounds
|
|
90
108
|
*literal* name/trigger reuse only — a post-cutoff duplicate with a *paraphrased* trigger is invisible to
|
|
91
109
|
both the judge (cutoff) and the grep (literal); that residual leans on the judged half **fed the
|
|
@@ -105,10 +123,22 @@ skipping. (Provenance: `tracks/_audit/session_2026_07_25_claude5-context-rules-s
|
|
|
105
123
|
|
|
106
124
|
## Done When
|
|
107
125
|
|
|
126
|
+
Each condition declares its check class (mandatory-pass / measured / judged); every judged condition
|
|
127
|
+
names its adversarial pairing — no judge-only path.
|
|
128
|
+
|
|
108
129
|
```
|
|
109
130
|
All steps 0–3 completed
|
|
131
|
+
(mandatory-pass — each step's output block is present; a skipped step is a FAIL, not a default pass)
|
|
132
|
+
+ Step 0.5 scan is LIVE: roster_entries > 0
|
|
133
|
+
(measured: the reported roster_entries count. 0 = SCAN_DEAD → criterion ④ UNDETERMINED and this
|
|
134
|
+
skill is NOT done — a dead scan and a genuine no-collision both read 0 collisions, so the
|
|
135
|
+
liveness number is what separates them)
|
|
110
136
|
+ Step 3 routing result output (location: FH meta-skill / local agent / drop)
|
|
137
|
+
(judged — adversarial pairing: `fh-meta:challenger` re-argues the case for the destination that was
|
|
138
|
+
NOT chosen, citing the 4 criteria; a routing verdict that survives the opposite case passes, an
|
|
139
|
+
unopposed one does not)
|
|
111
140
|
+ Next action specified (write SKILL.md / create .claude/agents/ / none)
|
|
141
|
+
(mandatory-pass — a literal next-action string from that enum; blank or "TBD" does not satisfy it)
|
|
112
142
|
```
|
|
113
143
|
|
|
114
144
|
---
|
|
@@ -103,11 +103,25 @@ probe localhost:11434 && echo "ollama-local(mac)"
|
|
|
103
103
|
EP="$FH_SIDECAR_EXTRA"
|
|
104
104
|
[ -z "$EP" ] && [ -f tracks/_meta/sidecar_endpoints.env ] && \
|
|
105
105
|
EP="$(grep '^OLLAMA_EXTRA=' tracks/_meta/sidecar_endpoints.env | cut -d= -f2- | tr -d '"')"
|
|
106
|
-
for e in $EP
|
|
107
|
-
|
|
106
|
+
# Split on NEWLINES via `while read`, never on an unquoted `for e in $EP`. Word-splitting an unquoted
|
|
107
|
+
# variable is a BASH behavior; zsh does NOT word-split, so under zsh a space-separated multi-endpoint
|
|
108
|
+
# list arrives as ONE string, hits the charclass below (space is not in it) and is dropped — silently
|
|
109
|
+
# reporting "no extra sidecars", i.e. the single-family fail-open this skill exists to prevent.
|
|
110
|
+
# Measured 2026-08-11: `EP="host1:11434 host2:11434"` → bash probes 2, zsh probes 0.
|
|
111
|
+
# Accepts either separator: commas/spaces are normalized to newlines first.
|
|
112
|
+
printf '%s\n' "$EP" | tr ' ,' '\n\n' | while IFS= read -r e; do
|
|
113
|
+
[ -z "$e" ] && continue
|
|
114
|
+
case "$e" in *[!0-9a-zA-Z.:-]*)
|
|
115
|
+
# NEVER a silent `continue` — a dropped endpoint must be visible, or an unprobed panel is
|
|
116
|
+
# indistinguishable from an unavailable one (DEGRADED_PANEL_UNUSED vs DEGRADED_SINGLE_FAMILY).
|
|
117
|
+
echo "sidecar-endpoint DROPPED (not host:port form): [$e]" >&2; continue;;
|
|
118
|
+
esac
|
|
108
119
|
probe "$e" 10 && echo "ollama-extra($e)" # -m10: a sleeping GPU box may wake slower than 6s
|
|
109
120
|
done
|
|
110
121
|
```
|
|
122
|
+
**Shell note**: this block is `sh`-portable and is written so bash and zsh behave identically. Any
|
|
123
|
+
future edit that reintroduces `for e in $EP` re-opens the zsh drop above. A drop line on stderr is a
|
|
124
|
+
**finding, not noise** — carry it into the Step 6 degrade verdict rather than discarding stderr.
|
|
111
125
|
Endpoint resolution is a **mechanical env/file read** (not a prose instruction the runner must remember),
|
|
112
126
|
so this discovery is tier-independent — no target-tier sim owed. The extra-endpoint binding lives only in
|
|
113
127
|
the gitignored `tracks/_meta/sidecar_endpoints.env` (auto-synced to the companion store); the public skill
|
|
@@ -29,13 +29,37 @@ ls -d */ 2>/dev/null | head -20
|
|
|
29
29
|
### Step 2 — Large file detection + warning format
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
# Detect files exceeding 500 lines (top 10)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
# Detect files exceeding 500 lines (top 10).
|
|
33
|
+
#
|
|
34
|
+
# Two mechanical guards, both measured 2026-08-11 on this repo:
|
|
35
|
+
# (a) 500-line THRESHOLD via awk. Without it, `head -11 | tail -10` emits 10 rows unconditionally —
|
|
36
|
+
# this repo's largest source file is 450 lines and ZERO files exceed 500, yet the old pipeline
|
|
37
|
+
# still returned 10 rows, which the warning block below then rendered as "Large file detected".
|
|
38
|
+
# Not-found must render as "none", never as a hit.
|
|
39
|
+
# (b) `while read` instead of `xargs wc -l`. xargs splits a long file list into batches and EACH
|
|
40
|
+
# batch emits its own `total` row; those rows then occupy slots in the reported top 10
|
|
41
|
+
# (measured: 6000 files -> 2 `total` rows, one of them inside the top 10). The loop also
|
|
42
|
+
# survives spaces in filenames, which the xargs form did not.
|
|
43
|
+
FILES="$(find . -type f \( -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" \
|
|
44
|
+
-o -name "*.java" -o -name "*.kt" \) \
|
|
45
|
+
-not -path "*/node_modules/*" -not -path "*/.git/*")"
|
|
46
|
+
SCANNED="$(printf '%s' "$FILES" | grep -c . )"
|
|
47
|
+
BIG="$(printf '%s\n' "$FILES" | while IFS= read -r f; do
|
|
48
|
+
[ -n "$f" ] || continue
|
|
49
|
+
printf '%s\t%s\n' "$(wc -l < "$f")" "$f"
|
|
50
|
+
done | awk -F'\t' '$1 > 500' | sort -rn | head -10)"
|
|
51
|
+
|
|
52
|
+
if [ "$SCANNED" -eq 0 ]; then
|
|
53
|
+
echo "large-file scan: UNMEASURED — 0 source files matched (wrong cwd, or this project uses other extensions)"
|
|
54
|
+
elif [ -z "$BIG" ]; then
|
|
55
|
+
echo "large-file scan: none — 0 of $SCANNED source files exceed 500 lines"
|
|
56
|
+
else
|
|
57
|
+
printf '%s\n' "$BIG"
|
|
58
|
+
fi
|
|
36
59
|
```
|
|
37
60
|
|
|
38
|
-
|
|
61
|
+
Emit the warning below **only for rows the scan actually returned** (`BIG` non-empty). A `none` or
|
|
62
|
+
`UNMEASURED` line is reported as-is and produces **no** warning — and `UNMEASURED` is not `none`:
|
|
39
63
|
|
|
40
64
|
```
|
|
41
65
|
⚠️ Large file detected: {filename} ({N} lines)
|
|
@@ -67,11 +91,22 @@ If found, suggest adding to the `## Check Items` or `## Token Efficiency` sectio
|
|
|
67
91
|
# CLAUDE.md line count
|
|
68
92
|
wc -l CLAUDE.md .claude/CLAUDE.md 2>/dev/null | sort -rn | head -3
|
|
69
93
|
|
|
70
|
-
#
|
|
71
|
-
wc -l memory/MEMORY.md 2>/dev/null
|
|
72
|
-
|
|
73
|
-
#
|
|
74
|
-
|
|
94
|
+
# Session memory lives OUTSIDE the repo — under the Claude Code project dir, keyed by a slug of the
|
|
95
|
+
# absolute cwd. There is NO `memory/` at the repo root: the old `wc -l memory/MEMORY.md 2>/dev/null`
|
|
96
|
+
# and `find memory ... 2>/dev/null` both printed nothing on this repo, and that silence read as
|
|
97
|
+
# "no bloat" (not-found rendered as zero). Derive the path; never hardcode a home path.
|
|
98
|
+
MEMDIR="$HOME/.claude/projects/$(pwd | sed 's|/|-|g')/memory"
|
|
99
|
+
if [ -d "$MEMDIR" ]; then
|
|
100
|
+
# MEMORY.md line count (200-line limit)
|
|
101
|
+
if [ -f "$MEMDIR/MEMORY.md" ]; then wc -l "$MEMDIR/MEMORY.md"
|
|
102
|
+
else echo "MEMORY.md: UNMEASURED — index absent under $MEMDIR"; fi
|
|
103
|
+
# topic files exceeding 30K (while-read: survives spaces, no xargs `total` rows)
|
|
104
|
+
find "$MEMDIR" -name "*.md" -size +30k | while IFS= read -r m; do
|
|
105
|
+
printf '%s\t%s\n' "$(wc -l < "$m")" "$m"
|
|
106
|
+
done | sort -rn | head -10
|
|
107
|
+
else
|
|
108
|
+
echo "memory audit: UNMEASURED — no memory dir at $MEMDIR. This is NOT 'zero bloat'."
|
|
109
|
+
fi
|
|
75
110
|
|
|
76
111
|
# SKILL.md files > 300 lines with no SKILL_detail.md (salience-splitter candidates)
|
|
77
112
|
find plugins -name "SKILL.md" 2>/dev/null | while read f; do
|
|
@@ -14,8 +14,13 @@ that corpus from multiple public-domain versions so grounding is robust and non-
|
|
|
14
14
|
verified in ANY version counts), without ever adding a generator.
|
|
15
15
|
|
|
16
16
|
> Origin: harvested from the-bible (2026-06-20) — 6 public-domain Bible versions, 197k verses, as the
|
|
17
|
-
> fail-closed grounding axiom.
|
|
18
|
-
>
|
|
17
|
+
> fail-closed grounding axiom. **The grounds, inline, because the harvest record does not ship**: one
|
|
18
|
+
> edition's wording makes a fail-closed check reject a faithful quote that followed a *different*
|
|
19
|
+
> edition, so the union across versions is what stops fail-closed grounding from failing closed
|
|
20
|
+
> *against the user* — and it keeps one translation's editorial choices from silently becoming the
|
|
21
|
+
> axiom. Generalizes to any verbatim-relay corpus (legal statute, RFC text, standards).
|
|
22
|
+
> Full harvest record — **hub-local, not distributed in the npm package**:
|
|
23
|
+
> `tracks/_contrib/field_harvest_2026-06-20_gate-locality-and-grounding-capabilities.md`.
|
|
19
24
|
|
|
20
25
|
## Triggers
|
|
21
26
|
- "get more sources" / "broaden the grounded corpus"
|
|
@@ -39,12 +44,16 @@ verified in ANY version counts), without ever adding a generator.
|
|
|
39
44
|
4. **Wire grounding as a union** — the grounding check passes if the quote matches the canonical text
|
|
40
45
|
at that key in ANY version. Never add a path that generates text — grounding is quote-only.
|
|
41
46
|
5. **Relay-integrity check** — confirm the consumer (the gate) QUOTES the corpus and cannot emit
|
|
42
|
-
un-grounded text; run a fabrication probe (a known non-source quote must fail-closed)
|
|
47
|
+
un-grounded text; run a fabrication probe (a known non-source quote must fail-closed) and write
|
|
48
|
+
the probe's **actual output** into the index under `probe_status:`. Writing the probe *spec*
|
|
49
|
+
without running it is `probe_status: not_run`, not a pass.
|
|
43
50
|
|
|
44
51
|
## Done When
|
|
45
52
|
- **Each added source carries a verifiable public-domain/license record** in the index. *Check class: mandatory-pass (binary — license field present and non-empty per version).*
|
|
46
|
-
- **
|
|
47
|
-
- **
|
|
53
|
+
- **The index enumerates every version that was ATTEMPTED, each carrying a status** — `fetched` | `failed(<reason>)` | `skipped(<reason>)` | `unknown`. A version that was tried and dropped appears with its reason; **absence from the list is not a zero**, it is an unrecorded drop. *Check class: mandatory-pass (binary — the attempted-version list is present and every entry carries one of the four statuses).*
|
|
54
|
+
- **Every version is normalized to the same key schema** (cross-version keys align). *Check class: mandatory-pass (a shared sample key resolves in each version). A key genuinely absent from a version is allowed ONLY when the index records it under `canon_scope:` — the reason plus the explicit list of affected keys and versions. An unrecorded exception is FAIL: "it's canon-scoped" asserted in prose and nowhere in the index does not satisfy this condition.*
|
|
55
|
+
- **The index declares the quote-only union contract** (grounding matches verbatim text in ANY version; no generation path). *Check class: mandatory-pass (binary — quote-only contract present in the index).*
|
|
56
|
+
- **The fabrication probe was RUN and its output shows fail-closed** — a known non-source quote was submitted to the consumer gate and refused, with the refusal output recorded in the index. *Check class: mandatory-pass (binary — `probe_status: executed` plus the attached refusal output). A probe **spec** with no run is `probe_status: not_run` and is a sub-condition, never this one.* **Degrade — labeled, never a silent pass**: no consumer gate exists yet → record `probe_status: no_consumer (<what is missing>)`; the corpus may still ship, but ships **labeled relay-unverified**, this condition stays UNMET, and nothing downstream may cite the corpus as relay-verified until a run is attached.
|
|
48
57
|
|
|
49
58
|
## Guards
|
|
50
59
|
- **Grounding, never a generator** — the relay constraint is structural; this skill wires *grounding*.
|
|
@@ -21,7 +21,7 @@ Automatically discovers cross-invocable pairs in environments with multiple inst
|
|
|
21
21
|
1. **Multi-ecosystem component environment specified**: "multiple plugins/cross-CLI installed", "synergy with other components", "cross-ecosystem", "run together"
|
|
22
22
|
2. **New component added/removed**: "component install", "add/remove component"
|
|
23
23
|
3. **Synergy check phrasing**: "are they working in isolation?", "can they be integrated?", "environment check", "combination effect"
|
|
24
|
-
4. **Registry change detected** (optional): If a user-maintained `LOCAL_SKILL_REGISTRY.md` is present, Step 7 runs when a new project/skill is registered. The registry is not auto-created — absent file → Step 7
|
|
24
|
+
4. **Registry change detected** (optional): If a user-maintained `LOCAL_SKILL_REGISTRY.md` is present, Step 7 runs when a new project/skill is registered. The registry is not auto-created — absent file → Step 7 reports `[NOT-CONFIGURED]` and skips its body (see Step 7-1 outcome table).
|
|
25
25
|
|
|
26
26
|
**Exception**: Single-component environments (1 or fewer installed → no meaningful activation)
|
|
27
27
|
|
|
@@ -40,15 +40,29 @@ Automatically discovers cross-invocable pairs in environments with multiple inst
|
|
|
40
40
|
| "Wouldn't combining these plugins be more powerful?" | Explore component combination synergies |
|
|
41
41
|
| "I feel like there's synergy here — find it" | Automatic cross-invocation pair discovery |
|
|
42
42
|
|
|
43
|
-
## Processing Steps (
|
|
43
|
+
## Processing Steps (7-step)
|
|
44
44
|
|
|
45
45
|
### Step 1. Installation Inventory Direct Inspection
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
48
|
cat ~/.claude/plugins/installed_plugins.json
|
|
49
|
-
# fields: name, version, installPath, gitCommitSha
|
|
50
49
|
```
|
|
51
50
|
|
|
51
|
+
**Schema (measured 2026-08-11, `version: 2`)** — read this before writing any parser:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
{"version": 2,
|
|
55
|
+
"plugins": { # DICT, not a list
|
|
56
|
+
"<plugin>@<marketplace>": [ # value is a LIST of entries
|
|
57
|
+
{"gitCommitSha": …, "installPath": …, "installedAt": …,
|
|
58
|
+
"lastUpdated": …, "scope": …, "version": …}
|
|
59
|
+
]}}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The plugin **name is the dict key**, not an entry field — `entry.get('name')` is always `None`,
|
|
63
|
+
and iterating `for pl in data['plugins']` yields **key strings**, not entry dicts.
|
|
64
|
+
`gitCommitSha` is **optional** (measured: present on 5 of 11 installs) — see Step 5 drift.
|
|
65
|
+
|
|
52
66
|
Additional checks:
|
|
53
67
|
- `~/.claude/settings.json` `enabledPlugins` (actually active assets)
|
|
54
68
|
- Check `installed_plugins.json` ↔ `enabledPlugins` consistency (catch drift)
|
|
@@ -56,15 +70,18 @@ Additional checks:
|
|
|
56
70
|
### Step 2. Asset Matrix Extraction per Component
|
|
57
71
|
|
|
58
72
|
```bash
|
|
59
|
-
|
|
60
|
-
ls
|
|
61
|
-
|
|
62
|
-
ls {installPath}/.mcp.json
|
|
63
|
-
ls {installPath}/hooks/
|
|
73
|
+
for T in skills agents commands .mcp.json hooks; do
|
|
74
|
+
if [ -e "$IP/$T" ]; then echo "PRESENT $T"; ls "$IP/$T"; else echo "ABSENT $T"; fi
|
|
75
|
+
done
|
|
64
76
|
```
|
|
65
77
|
|
|
66
78
|
Extract each asset's frontmatter `description` + `allowed-tools` + `model`. Merge `plugin.json keywords`.
|
|
67
79
|
|
|
80
|
+
**`ABSENT` is a state, not a zero.** Most plugins ship only a subset (measured on `fh-meta`:
|
|
81
|
+
`skills`/`agents` present, `commands`/`.mcp.json`/`hooks` absent). Carry `ABSENT` through to
|
|
82
|
+
the matrix — an absent asset class must not be counted as "0 assets found", which would read as
|
|
83
|
+
an inspected-and-empty component.
|
|
84
|
+
|
|
68
85
|
### Step 3. Cross-Invocation Possible Pair Matrix Derivation
|
|
69
86
|
|
|
70
87
|
Call mechanism compatibility:
|
|
@@ -88,15 +105,33 @@ Call mechanism compatibility:
|
|
|
88
105
|
|
|
89
106
|
- **cwd fragmentation**: Component A and B operating in different cwds → work area separation
|
|
90
107
|
- **Namespace conflict**: Same skill name exposed across multiple components simultaneously
|
|
91
|
-
- **Drift**: Install path commit SHA ↔ original repo HEAD mismatch
|
|
108
|
+
- **Drift**: Install path commit SHA ↔ original repo HEAD mismatch. **Three states, not two** —
|
|
109
|
+
`gitCommitSha` is absent on marketplace installs (measured: 6 of 11), and an absent SHA is
|
|
110
|
+
**`DRIFT-UNKNOWN` (cannot be checked)**, never "matches". Report `MATCH / DRIFTED /
|
|
111
|
+
DRIFT-UNKNOWN(n=…)` and **never fold `DRIFT-UNKNOWN` into the match count**
|
|
92
112
|
- **Hook conflict**: Same event matcher across multiple components → inspect settings.json integration
|
|
93
113
|
|
|
94
114
|
When risk found → user explicit decision gate (no automatic patching)
|
|
95
115
|
|
|
96
116
|
### Step 6. Result Persistence (Optional)
|
|
97
117
|
|
|
118
|
+
**Canonical result file** (the "synergy reference file" referenced throughout this skill):
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
tracks/_meta/synergy_scan_{YYYY-MM-DD}.md # local, gitignored by design
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Verified 2026-08-11 against the two on-disk candidates:
|
|
125
|
+
`tracks/_meta/synergy_scan_2026-07-31.md` **is** a synergy-pair ranking record and is the canon;
|
|
126
|
+
`knowledge/shared/harness-core/fh_synergy_playbook.md` is **not** — it is a tracked, public
|
|
127
|
+
integration playbook (FH × OpenCode / Hermes / OpenHuman workflows) with no pair registry.
|
|
128
|
+
|
|
129
|
+
**Residency**: a scan output enumerates the operator's installed components and mapped field
|
|
130
|
+
harnesses, which can carry company asset names. It belongs on a gitignored path only —
|
|
131
|
+
never append discovered pairs to a tracked file such as the playbook.
|
|
132
|
+
|
|
98
133
|
When persisting results:
|
|
99
|
-
- Record discovered synergy pairs in result file
|
|
134
|
+
- Record discovered synergy pairs in the canonical result file above
|
|
100
135
|
- Confirm absence of equivalent external tools (environment comparison verification)
|
|
101
136
|
|
|
102
137
|
### Step 7. Proactive Discovery — Proactive Mode
|
|
@@ -107,30 +142,55 @@ When persisting results:
|
|
|
107
142
|
|
|
108
143
|
#### 7-1. Dynamically Discover and Read Registry Path
|
|
109
144
|
|
|
145
|
+
The registry is a **per-machine, gitignored** artifact (regenerated by the session scan). It therefore
|
|
146
|
+
lives in the **working project**, not in the plugin cache — a plugin install path ships no `.claude/`
|
|
147
|
+
directory at all, so searching only there yields a permanent false skip on every external install.
|
|
148
|
+
|
|
110
149
|
```bash
|
|
111
|
-
#
|
|
150
|
+
# Resolve FH install path (fallback root only). stderr is deliberately NOT discarded.
|
|
112
151
|
FH_INSTALL=$(python3 -c "
|
|
113
152
|
import json, pathlib
|
|
114
153
|
p = pathlib.Path.home() / '.claude/plugins/installed_plugins.json'
|
|
115
154
|
if p.exists():
|
|
116
155
|
data = json.loads(p.read_text())
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
156
|
+
raw = data.get('plugins', data) if isinstance(data, dict) else data
|
|
157
|
+
# version 2 = dict keyed by name; legacy = list of entries carrying 'name'
|
|
158
|
+
items = raw.items() if isinstance(raw, dict) else [(e.get('name',''), [e]) for e in raw]
|
|
159
|
+
for name, entries in items:
|
|
160
|
+
entry = entries[0] if isinstance(entries, list) else entries
|
|
161
|
+
if 'forge-harness' in name:
|
|
162
|
+
print(entry.get('installPath',''))
|
|
121
163
|
break
|
|
122
|
-
"
|
|
164
|
+
")
|
|
165
|
+
py_rc=$?
|
|
123
166
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
167
|
+
if [ "$py_rc" -ne 0 ]; then
|
|
168
|
+
echo "[HARNESS_ERROR] installed_plugins.json read failed (python rc=$py_rc)."
|
|
169
|
+
echo " Step 7 state = UNMEASURED. Do NOT report this as '[SKIP] no registry' — the inventory was never read."
|
|
127
170
|
else
|
|
128
|
-
|
|
129
|
-
|
|
171
|
+
REGISTRY=""
|
|
172
|
+
for CAND in "${CLAUDE_PROJECT_DIR:-$PWD}/.claude/registry/LOCAL_SKILL_REGISTRY.md" \
|
|
173
|
+
"${FH_INSTALL:+$FH_INSTALL/.claude/registry/LOCAL_SKILL_REGISTRY.md}"; do
|
|
174
|
+
if [ -n "$CAND" ] && [ -f "$CAND" ]; then REGISTRY="$CAND"; break; fi
|
|
175
|
+
done
|
|
176
|
+
if [ -n "$REGISTRY" ]; then
|
|
177
|
+
cat "$REGISTRY"
|
|
178
|
+
else
|
|
179
|
+
echo "[NOT-CONFIGURED] LOCAL_SKILL_REGISTRY.md absent (searched \$CLAUDE_PROJECT_DIR/.claude/registry/ then \$FH_INSTALL/.claude/registry/)."
|
|
180
|
+
echo " Create: mkdir -p \"\${CLAUDE_PROJECT_DIR:-\$PWD}/.claude/registry\" and write LOCAL_SKILL_REGISTRY.md there (per-machine, gitignored by design)."
|
|
181
|
+
fi
|
|
130
182
|
fi
|
|
131
183
|
```
|
|
132
184
|
|
|
133
|
-
|
|
185
|
+
**Three outcomes, reported distinctly** (a missing measurement is not a zero):
|
|
186
|
+
|
|
187
|
+
| Outcome | Meaning | Step 7 body |
|
|
188
|
+
|---|---|---|
|
|
189
|
+
| registry printed | configured and read | run 7-2 ~ 7-5 |
|
|
190
|
+
| `[NOT-CONFIGURED]` | inventory read fine, no registry exists | skip 7-2 ~ 7-5, report this state + the creation hint |
|
|
191
|
+
| `[HARNESS_ERROR]` | inventory could not be read | skip 7-2 ~ 7-5, report **UNMEASURED** — never as a skip or a clean result |
|
|
192
|
+
|
|
193
|
+
If the registry was printed, extract `one-line description` + `example phrases` from newly registered projects/skills.
|
|
134
194
|
|
|
135
195
|
#### 7-2. Load Existing Synergy Pair List
|
|
136
196
|
|
|
@@ -156,10 +216,10 @@ Compare domain of new skill/project against entire existing registry:
|
|
|
156
216
|
|---|---|---|---|
|
|
157
217
|
| 1 | `{new skill}` ↔ `{existing skill}` | ★★★ | {one-line description} |
|
|
158
218
|
|
|
159
|
-
→ Add to
|
|
219
|
+
→ Add to the canonical result file (Step 6: `tracks/_meta/synergy_scan_{YYYY-MM-DD}.md`)? [Y / N]
|
|
160
220
|
```
|
|
161
221
|
|
|
162
|
-
- **Y** →
|
|
222
|
+
- **Y** → Append to that file as a new pair section (gitignored path only — see Step 6 Residency)
|
|
163
223
|
- **N** → Collect reason and discard or defer recording
|
|
164
224
|
|
|
165
225
|
#### 7-5. Guards
|
|
@@ -182,12 +242,15 @@ External users automatically derive their own inventory via Step 1 `installed_pl
|
|
|
182
242
|
|
|
183
243
|
## Done When
|
|
184
244
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
245
|
+
| Condition | Check class |
|
|
246
|
+
|---|---|
|
|
247
|
+
| Steps 1~6 completed | **mandatory-pass** |
|
|
248
|
+
| Synergy ranking table (★~★★★) output | **mandatory-pass** |
|
|
249
|
+
| **Step 7 state reported as one of `run` / `not-configured` / `harness-error`** — never silently omitted, and `harness-error` never reported as a skip | **mandatory-pass** |
|
|
250
|
+
| Step 5 drift reported as `MATCH / DRIFTED / DRIFT-UNKNOWN(n=…)`, with `DRIFT-UNKNOWN` excluded from the match count; Step 2 `ABSENT` asset classes carried through as `ABSENT`, not `0` | **measured** (counts come from the Step 1/2 output, not from recall) |
|
|
251
|
+
| User explicit decision gate completed if risk catch items exist | **mandatory-pass** |
|
|
252
|
+
| Synergy grades are defensible (★ assignment per the Step 4 table) | **judged** — adversarial pairing: `fh-meta:challenger` re-reads the pair list and attacks each ★★★ for "would these two actually chain, or do they merely sound adjacent?" |
|
|
253
|
+
| User confirmed whether to persist results | **mandatory-pass** |
|
|
191
254
|
|
|
192
255
|
## Constraints
|
|
193
256
|
|
|
@@ -83,13 +83,31 @@ Draft the spec first, then single confirmation: "Is this the right direction?"
|
|
|
83
83
|
|
|
84
84
|
## Step 3. Generate Spec Document
|
|
85
85
|
|
|
86
|
-
Structure and save the results of the conversation.
|
|
86
|
+
Structure and save the results of the conversation. **This step writes a file** — outputting the
|
|
87
|
+
path is not saving it.
|
|
88
|
+
|
|
89
|
+
1. Derive the slug: `slug = kebab-case(spec title) + "-" + YYYYMMDD`
|
|
90
|
+
(lowercase, non-alphanumerics → `-`, collapse repeats, strip leading/trailing `-`).
|
|
91
|
+
Example: "Rewrite the login flow" on 2026-08-11 → `rewrite-the-login-flow-20260811`.
|
|
92
|
+
2. If `.claude/specs/{slug}.md` **already exists → ABORT** and report the existing path.
|
|
93
|
+
Never overwrite and never silently suffix — an existing spec is a prior decision to extend or
|
|
94
|
+
supersede, and that is the user's call.
|
|
95
|
+
3. Create the directory, then write the file with the **Write** tool (not a shell redirect):
|
|
87
96
|
|
|
88
97
|
```bash
|
|
89
|
-
|
|
90
|
-
.claude/specs/{task-slug}.md
|
|
98
|
+
mkdir -p .claude/specs
|
|
91
99
|
```
|
|
92
100
|
|
|
101
|
+
Then `Write` → `.claude/specs/{slug}.md` with the format below, and verify:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
test -f .claude/specs/{slug}.md && echo "SPEC SAVED: .claude/specs/{slug}.md"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Residency**: the spec records the user's goals, constraints, and "must not touch" list.
|
|
108
|
+
`.claude/specs/` is gitignored in this repo; **in a company project, confirm the path is gitignored
|
|
109
|
+
there too before writing** — if it is not, write to a gitignored location instead.
|
|
110
|
+
|
|
93
111
|
### Spec Document Format
|
|
94
112
|
|
|
95
113
|
```markdown
|
|
@@ -127,7 +145,7 @@ After generating the spec document, suggest the appropriate next path:
|
|
|
127
145
|
| Situation | Connected skill |
|
|
128
146
|
|---|---|
|
|
129
147
|
| Agent orchestration needed for implementation | `agent-composer` — pass spec document path |
|
|
130
|
-
| Plan / design review needed | `
|
|
148
|
+
| Plan / design review needed | built-in `Plan` agent — build plan based on spec |
|
|
131
149
|
| Single task is now clear | Start implementation directly |
|
|
132
150
|
| Audit needed before external sharing | `hub-persona-auditor` |
|
|
133
151
|
|
|
@@ -135,10 +153,11 @@ After generating the spec document, suggest the appropriate next path:
|
|
|
135
153
|
|
|
136
154
|
## Done When
|
|
137
155
|
|
|
138
|
-
| Condition | Completion verdict |
|
|
139
|
-
|
|
140
|
-
| Socratic dialogue complete
|
|
141
|
-
|
|
|
142
|
-
|
|
|
156
|
+
| Condition | Completion verdict | Check class |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| Socratic dialogue complete (≤3 rounds, ≤2 questions/round) | ✅ Clarification complete | **mandatory-pass** |
|
|
159
|
+
| `test -f .claude/specs/{slug}.md` exits 0 — the file **exists on disk** | ✅ Save complete | **mandatory-pass** (a printed path is not a saved file) |
|
|
160
|
+
| The spec's Completion Criteria are independently verifiable — someone other than the author could tell whether each is met | ✅ Spec actionable | **judged** — adversarial pairing: `fh-meta:beginner` cold-reads the spec and attempts to state, per criterion, how they would check it; a criterion they cannot operationalize fails |
|
|
161
|
+
| Follow-up skill connection suggestion output | ✅ Handoff complete | **mandatory-pass** |
|
|
143
162
|
|
|
144
163
|
**This skill's Done When = "actionable spec document saved".** Implementation itself is the domain of follow-up agents/skills.
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
name: fh
|
|
3
3
|
description: Renders the FH hub map on demand — the door menu, a starter set of skills, and the most-used trigger phrases — without requiring a greeting. State-aware; composes live candidates from the session card and tracks.
|
|
4
4
|
user-invocable: true
|
|
5
|
+
allowed-tools: ["Read", "Grep", "Glob"]
|
|
6
|
+
# /fh is read-only by construction: it detects state and renders a map. It was the only one of
|
|
7
|
+
# the 40 SKILL.md files with no allowed-tools declaration at all. Read/Grep/Glob is the full set
|
|
8
|
+
# its body needs — no Bash, Write, Edit, or Agent appears anywhere in it.
|
|
5
9
|
---
|
|
6
10
|
|
|
7
11
|
# /fh — hub map on demand
|