@antoneeo/kb-agentic-skill 1.13.0 → 1.14.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/CHANGELOG.md +29 -0
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/skills/kb-agentic-skill/ENFORCEMENT.md +23 -15
- package/skills/kb-agentic-skill/SKILL.md +1 -1
- package/skills/kb-agentic-skill/guides.md +16 -12
- package/skills/kb-agentic-skill/scripts/sdlc_check.py +13 -24
- package/skills/kb-agentic-skill/scripts/sdlc_core.py +54 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
Every significant change to this skill is recorded here.
|
|
4
4
|
|
|
5
|
+
## [1.14.0] - 2026-09-06
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **F-046: the protocol reaches every turn (`remind`, UserPromptSubmit, wired by
|
|
9
|
+
default).** `orient` fires once at session start and decays; a session that
|
|
10
|
+
never loads the skill never had the protocol at all. Measured 2026-09-06: a
|
|
11
|
+
release ran against a `GUIDE_release.md` the session never consulted, because
|
|
12
|
+
`SKILL.md` -- where the duty is written -- had not been read. `remind` prints
|
|
13
|
+
ONE constant line at every prompt, and its first duty is that one: decide
|
|
14
|
+
whether the skill governs the work in front of you and, if it does, LOAD it
|
|
15
|
+
once. The carrier is kb's F-041 item B, LIFTED into the shared spine rather
|
|
16
|
+
than duplicated, so all three lenses share one machine; each lens declares its
|
|
17
|
+
own line in `set_profile(remind_line=...)`. Installing the package wires it
|
|
18
|
+
machine-wide on Claude Code alongside the orientation hook, never instead of
|
|
19
|
+
it; removing the hook entry is a standing opt-out. Per-turn cost disclosed and
|
|
20
|
+
accepted by the owner (`vision/rulings.md` r19, the "no ceremony ratchet"
|
|
21
|
+
Non-Goal's second door), and bounded to stay flat by a contract the new shared
|
|
22
|
+
`scripts/test_remind.py` guards: constant text, zero reads, one line under 500
|
|
23
|
+
characters, argv ignored whole, always exit 0.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- **`guides.md` said something false about code guides.** It claimed `stale`
|
|
27
|
+
works unchanged for `source_kind: code` because "the code-excerpt snapshot
|
|
28
|
+
drifts when the code changes". A snapshot is a frozen copy and never drifts:
|
|
29
|
+
freshness is NOT mechanized there, and the duty is the author's twice -- when
|
|
30
|
+
you MODIFY code a comprehension guide describes, and when you merely READ one
|
|
31
|
+
before trusting it. Measured 2026-09-06: the guided module had gained 388
|
|
32
|
+
lines and lost 71 across four commits with `stale` silent.
|
|
33
|
+
|
|
5
34
|
## [1.13.0] - 2026-09-05
|
|
6
35
|
|
|
7
36
|
Spine-only release: `review.md` updated byte-identical across the family
|
package/gemini-extension.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kb-agentic-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "Knowledge-Base & Document-First protocol with risk triage, Vision governance, signal distillation and optional devPNT integration.",
|
|
5
5
|
"author": "Antonio Pinto (https://github.com/Antoneeo)"
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antoneeo/kb-agentic-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "Knowledge-Base & Document-First protocol for Claude Code, Gemini CLI, Google Antigravity and Codex with risk triage, Vision governance, signal distillation and optional devPNT integration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -202,20 +202,28 @@ Gemini CLI — wire the same command into its startup-hook mechanism if present;
|
|
|
202
202
|
- **Hybrid/devPNT projects**: add `--hybrid` — the hook then appends a one-line pointer to run `devpnt_mcp_get_bootstrap` for the Master Plan / Knowledge Layer and does not replicate them; the filesystem orientation (router + handoff + README) still emits.
|
|
203
203
|
- Like the CI gate (§2), if you copied `sdlc_check.py` into the repo, the hook references that copy — keep it current when you update the skill.
|
|
204
204
|
|
|
205
|
-
### Per-turn reminder: `remind` (UserPromptSubmit --
|
|
206
|
-
|
|
207
|
-
`orient` fires once, at session start; a long session drifts after it
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
the
|
|
205
|
+
### Per-turn reminder: `remind` (UserPromptSubmit -- wired by default)
|
|
206
|
+
|
|
207
|
+
`orient` fires once, at session start; a long session drifts after it, and a session
|
|
208
|
+
that never loads the skill never had the protocol at all. Measured (F-046, 2026-09-06):
|
|
209
|
+
a release ran against a `GUIDE_release.md` the session never consulted, because
|
|
210
|
+
`SKILL.md` -- where the duty is written -- had not been read. `sdlc_check.py remind` prints
|
|
211
|
+
ONE constant line at every prompt, and its first duty is that one: decide whether the
|
|
212
|
+
skill governs the work in front of you and, if it does, load it once.
|
|
213
|
+
|
|
214
|
+
Cost: 443 characters, ~75 tokens per prompt, paid on every turn including
|
|
215
|
+
trivial ones. That is admissible only because the owner accepted it explicitly
|
|
216
|
+
(`ai_docs/vision/rulings.md` r19, the "no ceremony ratchet" Non-Goal's second door) --
|
|
217
|
+
and the acceptance was for a FLAT cost. Hence the contract, guarded by
|
|
218
|
+
`scripts/test_remind.py`: the line is **constant and reads nothing** (so nothing repo-
|
|
219
|
+
or session-controlled rides into the agent's context through it, and the cost cannot
|
|
220
|
+
grow with the session), it is **one line under 500 characters**, and it **can never
|
|
221
|
+
break a prompt** (argv ignored whole, always exit 0). A trivial turn pays a yes/no
|
|
222
|
+
judgement, never a load.
|
|
223
|
+
|
|
224
|
+
Installing the package wires it machine-wide on Claude Code, alongside the orientation
|
|
225
|
+
hook and never instead of it; **removing that hook entry is a standing opt-out.** To
|
|
226
|
+
wire it by hand:
|
|
219
227
|
|
|
220
228
|
```json
|
|
221
229
|
{
|
|
@@ -225,7 +233,7 @@ the validator path is machine-specific, same rule as the orientation hook above)
|
|
|
225
233
|
"hooks": [
|
|
226
234
|
{
|
|
227
235
|
"type": "command",
|
|
228
|
-
"command": "python \"C
|
|
236
|
+
"command": "python \"C:\Users\<user>\.claude\skills\kb-agentic\scripts\sdlc_check.py\" remind"
|
|
229
237
|
}
|
|
230
238
|
]
|
|
231
239
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kb-agentic
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.14.0
|
|
4
4
|
description: Knowledge-Base & Document-First protocol with risk-proportional triage, Vision as a guide, Signal Distillation, a complete Standalone mode and optional symbiosis with devPNT. Use for user documentation, knowledge extraction, SOPs, research notes, decision logs, knowledge management — and for answering project questions from the claim ledger and topic graph.
|
|
5
5
|
author: Antonio Pinto (https://github.com/Antoneeo)
|
|
6
6
|
copyright: (c) 2026 Antonio Pinto
|
|
@@ -60,6 +60,10 @@ already cover how to do this well?*
|
|
|
60
60
|
match was not targeted (T7). Two guides are legitimate only when they cover
|
|
61
61
|
distinct concerns — typically an operative guide plus the comprehension map of
|
|
62
62
|
the component being touched; three is a smell, not a thorough lookup.
|
|
63
|
+
- **Check a `code` guide against the code before you trust it.** No check can do
|
|
64
|
+
this for you (§6): the reader is the only one who sees that the map and the
|
|
65
|
+
component have parted. A divergence you observe is yours to close in the same
|
|
66
|
+
unit of work.
|
|
63
67
|
- **Under subagent dispatch** the consult happens at plan-authoring time (the
|
|
64
68
|
orchestrator populates each task's `guides` field); a context-free subagent
|
|
65
69
|
reads the pointers it was handed and does not run its own router lookup. See
|
|
@@ -271,17 +275,17 @@ state it explicitly when handing off a newly created guide.
|
|
|
271
275
|
|
|
272
276
|
## 6. Maintenance
|
|
273
277
|
|
|
274
|
-
- **Source changed**:
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
and
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
278
|
+
- **Source changed**: new snapshot, regenerate the guide from it (new
|
|
279
|
+
`source_hash`); a guide REPLACING another is `status: SUPERSEDED` on the old
|
|
280
|
+
one. `sdlc_check.py stale` (also under `--hybrid`) reports `[stale]` when a
|
|
281
|
+
guide's recorded hash and its snapshot file diverge — the signal to regenerate.
|
|
282
|
+
- **`source_kind: code` freshness is NOT mechanized.** `stale` compares the guide
|
|
283
|
+
to its snapshot, and a code snapshot is a frozen copy — so a map whose component
|
|
284
|
+
was rewritten reports FRESH forever (measured 2026-09-06: +388/-71 lines in the
|
|
285
|
+
guided module, `stale` silent). The duty is therefore the author's, twice: when
|
|
286
|
+
you MODIFY code a comprehension guide describes, refresh the guide in the same
|
|
287
|
+
closure (docs travel with the code); when you merely READ one, check it against
|
|
288
|
+
the code before trusting it. Too large to absorb → mark it `SUPERSEDED` rather
|
|
289
|
+
than leave a confident-wrong map badged CURRENT, which is worse than none.
|
|
286
290
|
- **Agent-global KB guides** use the same pipeline and validator via
|
|
287
291
|
`--root ~/.agentic-sdlc`; freshness via the same `stale` engine.
|
|
@@ -80,6 +80,19 @@ sdlc_core.set_profile(
|
|
|
80
80
|
# sdlc_core.py in three distributions to buy nothing.
|
|
81
81
|
"taxonomy_pass", "subagent_dispatch", "question_discipline",
|
|
82
82
|
),
|
|
83
|
+
# F-046: the per-turn line moved from this file's own `remind` command into
|
|
84
|
+
# the shared spine, which now carries the machine for all three lenses. The
|
|
85
|
+
# kb duties below are unchanged; what is new is the first one -- an unread
|
|
86
|
+
# protocol cannot be applied, and until now nothing said so.
|
|
87
|
+
remind_line=(
|
|
88
|
+
"first decide if this skill governs the work; if yes, LOAD it once -- an "
|
|
89
|
+
"unread protocol cannot be applied. Triage: L1 quick fact, L2 propagation, "
|
|
90
|
+
"L3 new knowledge unit, Spike; declare the level. On this project's "
|
|
91
|
+
"domain, read topics/INDEX.md first and cite claim ids, or state no "
|
|
92
|
+
"coverage. Decisions today get recorded in the KB at close. Revising a "
|
|
93
|
+
"document? Re-read it whole and rewrite to current state -- never append "
|
|
94
|
+
"a delta."
|
|
95
|
+
),
|
|
83
96
|
design_gate_between=("### 3. Request Analysis & Taxonomy Pass",
|
|
84
97
|
"### 4. Knowledge Processing & Distillation"),
|
|
85
98
|
)
|
|
@@ -1884,26 +1897,6 @@ def kb_cmd_orient(argv):
|
|
|
1884
1897
|
return rc
|
|
1885
1898
|
|
|
1886
1899
|
|
|
1887
|
-
def kb_cmd_remind(_argv):
|
|
1888
|
-
"""F-041 item B: the per-turn one-line reminder (UserPromptSubmit, opt-in).
|
|
1889
|
-
|
|
1890
|
-
A CONSTANT, zero-read line -- the kb minimum an agent needs re-armed every
|
|
1891
|
-
prompt: triage, the recall trigger, the capture moment, the revision gesture. Constant by
|
|
1892
|
-
contract: nothing repo-controlled may ride a line injected into the agent's
|
|
1893
|
-
context every turn, and zero reads is what keeps the per-turn cost flat.
|
|
1894
|
-
The vision's non-goal bans per-turn GRAPH queries; this line only re-arms
|
|
1895
|
-
the entry-into-topic criterion, it never runs the descent. Never wired by
|
|
1896
|
-
init and never a default: ENFORCEMENT par.4 documents the manual snippet
|
|
1897
|
-
and the ~50 tokens/prompt cost -- the project chooses. Fail-open like every
|
|
1898
|
-
hook surface: argv is ignored whole, the exit code is always 0."""
|
|
1899
|
-
print("kb-agentic: triage before acting -- L1 quick fact, L2 propagation of "
|
|
1900
|
-
"settled knowledge, L3 new knowledge unit, Spike exploration; declare "
|
|
1901
|
-
"the level. Answering about this project's domain? Read topics/INDEX.md "
|
|
1902
|
-
"under the docs root first and cite claim ids, or state no coverage. "
|
|
1903
|
-
"Decisions made today get recorded in the KB at session close. Revising an existing document? Re-read it whole and rewrite it to current state -- never append a delta.")
|
|
1904
|
-
return 0
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
1900
|
def kb_cmd_help():
|
|
1908
1901
|
"""The spine's usage, then the overlay's own commands.
|
|
1909
1902
|
|
|
@@ -1946,10 +1939,6 @@ def main(argv=None):
|
|
|
1946
1939
|
# spine runs it on the raw argv, the overlay only appends the topic router.
|
|
1947
1940
|
if argv and argv[0] == "orient":
|
|
1948
1941
|
return kb_cmd_orient(argv)
|
|
1949
|
-
# `remind` too: it is a hook surface (UserPromptSubmit), so a stray flag
|
|
1950
|
-
# must print the line, not an argparse usage error into someone's prompt.
|
|
1951
|
-
if argv and argv[0] == "remind":
|
|
1952
|
-
return kb_cmd_remind(argv)
|
|
1953
1942
|
# Forward-by-default: anything not intercepted goes to the spine untouched.
|
|
1954
1943
|
# Never a hand-copied command tuple - that is how a spine command gets
|
|
1955
1944
|
# silently dropped (mkt_check.py ships that exact defect with `migrate`).
|
|
@@ -268,16 +268,18 @@ _PROFILE = {
|
|
|
268
268
|
"support_files": (),
|
|
269
269
|
"capabilities": frozenset(),
|
|
270
270
|
"design_gate_between": (),
|
|
271
|
+
"remind_line": "",
|
|
271
272
|
}
|
|
272
273
|
|
|
273
274
|
|
|
274
275
|
def set_profile(skill_name, support_files=(), capabilities=(), unit_noun="feature",
|
|
275
|
-
design_gate_between=()):
|
|
276
|
+
design_gate_between=(), remind_line=""):
|
|
276
277
|
_PROFILE.update(skill_name=skill_name,
|
|
277
278
|
unit_noun=unit_noun,
|
|
278
279
|
support_files=tuple(support_files),
|
|
279
280
|
capabilities=frozenset(capabilities),
|
|
280
|
-
design_gate_between=tuple(design_gate_between)
|
|
281
|
+
design_gate_between=tuple(design_gate_between),
|
|
282
|
+
remind_line=remind_line)
|
|
281
283
|
|
|
282
284
|
|
|
283
285
|
def profile():
|
|
@@ -1796,6 +1798,43 @@ def cmd_check(root, strict=False, hybrid=False):
|
|
|
1796
1798
|
|
|
1797
1799
|
# --------------------------------------------------------------------- gate
|
|
1798
1800
|
|
|
1801
|
+
# --- UserPromptSubmit reminder hook (F-046) --------------------------------
|
|
1802
|
+
# `orient` fires once per session and decays; a session that never invokes the
|
|
1803
|
+
# skill never had the protocol at all. Measured 2026-09-06: a release ran in
|
|
1804
|
+
# this repo against a `GUIDE_release.md` the session never consulted, because
|
|
1805
|
+
# SKILL.md -- where the duty is written -- had not been read.
|
|
1806
|
+
#
|
|
1807
|
+
# The carrier is kb's (F-041 item B), lifted here so all three lenses share one
|
|
1808
|
+
# machine instead of two that do the same thing. Its contract is kept: the line
|
|
1809
|
+
# is CONSTANT and reads NOTHING -- nothing repo- or session-controlled may ride
|
|
1810
|
+
# text injected every turn, and zero reads is what keeps the per-turn cost flat.
|
|
1811
|
+
# What changed is the payload's first duty and the wiring. First duty: decide
|
|
1812
|
+
# whether the skill governs this work and, if it does, read it once -- an
|
|
1813
|
+
# unread protocol cannot be applied, which is the failure above. Wiring: a
|
|
1814
|
+
# default instead of opt-in, on the owner's explicit acceptance of the per-turn
|
|
1815
|
+
# cost (`vision/rulings.md` r19; the "no ceremony ratchet" Non-Goal admits a
|
|
1816
|
+
# never-zero cost by that acceptance, and a trivial turn pays a yes/no
|
|
1817
|
+
# judgement, never a load).
|
|
1818
|
+
|
|
1819
|
+
REMIND_FALLBACK = (
|
|
1820
|
+
"decide whether the {skill} skill governs this work; if it does, load it "
|
|
1821
|
+
"once before acting -- an unread protocol cannot be applied."
|
|
1822
|
+
)
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
def cmd_remind(args):
|
|
1826
|
+
"""UserPromptSubmit hook: print the lens's constant per-turn line. Always 0.
|
|
1827
|
+
|
|
1828
|
+
argv is ignored whole and nothing is read: a hook surface must not fail, and
|
|
1829
|
+
a flag typo must not cost a turn's context."""
|
|
1830
|
+
try:
|
|
1831
|
+
prof = profile()
|
|
1832
|
+
line = prof.get("remind_line") or REMIND_FALLBACK.format(skill=prof["skill_name"])
|
|
1833
|
+
print(f"{prof['skill_name']}: {line}")
|
|
1834
|
+
except Exception:
|
|
1835
|
+
pass
|
|
1836
|
+
return 0
|
|
1837
|
+
|
|
1799
1838
|
def cmd_gate(args):
|
|
1800
1839
|
file_path = args.file or ""
|
|
1801
1840
|
if args.hook:
|
|
@@ -2229,6 +2268,12 @@ def cmd_migrate(root, args):
|
|
|
2229
2268
|
# --------------------------------------------------------------------- main
|
|
2230
2269
|
|
|
2231
2270
|
def main(argv=None):
|
|
2271
|
+
# `remind` is intercepted BEFORE argparse (kb's F-041 rule, kept): it is a
|
|
2272
|
+
# hook surface fired on every prompt, so a stray flag must cost a usage
|
|
2273
|
+
# message and a non-zero exit on a turn, not the turn itself.
|
|
2274
|
+
if (argv if argv is not None else sys.argv[1:])[:1] == ["remind"]:
|
|
2275
|
+
return cmd_remind(None)
|
|
2276
|
+
|
|
2232
2277
|
common = argparse.ArgumentParser(add_help=False)
|
|
2233
2278
|
common.add_argument("--root", help="project root (default: walk up until a docs root is found)")
|
|
2234
2279
|
common.add_argument("--docs-dir", dest="docs_dir",
|
|
@@ -2273,6 +2318,10 @@ def main(argv=None):
|
|
|
2273
2318
|
sub.add_parser("orient", parents=[common, hybrid_opt],
|
|
2274
2319
|
help="SessionStart hook: emit docs-root orientation to stdout (fail-open, zero-execution)")
|
|
2275
2320
|
|
|
2321
|
+
sub.add_parser("remind", parents=[common],
|
|
2322
|
+
help="UserPromptSubmit hook: print the constant per-turn line "
|
|
2323
|
+
"(fail-open, zero-read, zero-execution)")
|
|
2324
|
+
|
|
2276
2325
|
pp = sub.add_parser("plan", parents=[common],
|
|
2277
2326
|
help="Subagent Execution: validate/brief a PLAN_[feature].md (zero-execution)")
|
|
2278
2327
|
pp_sub = pp.add_subparsers(dest="plan_cmd", required=True)
|
|
@@ -2296,7 +2345,7 @@ def main(argv=None):
|
|
|
2296
2345
|
# nothing is being guessed. Refusing here would make the guard block the
|
|
2297
2346
|
# one command that ends the ambiguity.
|
|
2298
2347
|
discovered, name = None, args.from_dir
|
|
2299
|
-
elif args.cmd
|
|
2348
|
+
elif args.cmd in ("orient", "remind"):
|
|
2300
2349
|
# The SessionStart hook is fail-open by contract: it must never block a
|
|
2301
2350
|
# session, not even on a half-migrated tree. It orients on the default
|
|
2302
2351
|
# and says so rather than exiting non-zero.
|
|
@@ -2311,6 +2360,8 @@ def main(argv=None):
|
|
|
2311
2360
|
return cmd_gate(args)
|
|
2312
2361
|
if args.cmd == "orient":
|
|
2313
2362
|
return cmd_orient(args)
|
|
2363
|
+
if args.cmd == "remind":
|
|
2364
|
+
return cmd_remind(args)
|
|
2314
2365
|
|
|
2315
2366
|
root = Path(args.root).resolve() if args.root else (discovered or find_project_root())
|
|
2316
2367
|
if args.cmd == "check":
|