feat(skills): staged, opt-in auto-skill generation (lifecycle + dedupe + scripts + crystallize) + Settings toggle - #392
Conversation
GPT 5.6 Review — ✅ human override acceptedHuman judgment by @iamwhatever overrides the GPT 5.6 finding for This comment is updated in place on each push. The model was not re-run because an authorized human decision supersedes it. False positive or not applicable? A repository writer can comment: |
Design Review (Fable 5) — 🟡 CONCERNSAdvisory design-level review of Design-Verdict: CONCERNS Sound staged pipeline, but the crystallize write path bypasses the repo's MCP-first boundary and the description contradicts the diff on the headline default. Watch
Suggestions
[DESIGN-REVIEWED] 6ff260d |
Opus 5 Review — ✅ human override acceptedReviewed Human judgment by @iamwhatever overrides the Opus 5 finding for Verdict recorded from an authorized human decision for commit False positive or not applicable? A repository writer can comment: |
Arbiter — ✅ no blocking findingsArbiter found no unresolved long-term items that require action before merging Second-order review for Review detailsArbiter-Verdict: PASS No sub-threshold finding meets the long-term-impact bar. Both line-level reviews (Opus 5, GPT 5.6) carry human overrides recorded as authoritative for this commit, leaving no line-level Medium/Low findings to judge. The design reviewer's three Watch items and one Suggestion were each weighed against the one-way-door and concrete-harm tests; none clears the bar, as detailed below. Suggested follow-ups (open as issues — non-blocking)
[ARBITER-REVIEWED] 6ff260d False positive or not applicable? A repository writer can comment: For a broader accepted-risk deferral, apply |
785800a to
513a01c
Compare
|
Addressed all review findings in GPT 5.6 — HIGH (skills.py: stale scripts on re-stage): GPT 5.6 — HIGH (prompts.py: blocking FS on event loop): the pending GPT 5.6 — MEDIUM (scripts rendered as a top-level key): the Arbiter — validate at the promotion choke point: Arbiter — dead cron-reference import: implemented Added tests: approve-time re-validation of directly-written pending scripts ( |
513a01c to
39ef28b
Compare
|
Addressed the second-round findings in HIGH — validator regex denylist is bypassable ( HIGH — approval UI approved blind: the Pending review panel now has a Review toggle per candidate that fetches the detail endpoint and shows the full MEDIUM — MEDIUM — default-on vs. spec doc: enabling-by-default is an explicit product decision from the PR author; rather than revert it, I updated the governing spec ( Backend Lint & Type Check (3.10/3.12) is green after the earlier flake8 fixes. |
39ef28b to
ddd23e1
Compare
|
Addressed the round-4 findings: HIGH — symlink TOCTOU in HIGH — Also fixed the mypy failure the lint gate caught ( |
ddd23e1 to
188234e
Compare
|
Addressed the round-5 findings: HIGH — read handlers weren't audited: MEDIUM — absolute path leak: |
3bcf647 to
cb3ec9b
Compare
|
Addressed in HIGH — crystallize content reaching dashboard/live unredacted (
Chose choke-point redaction over a new The prior two HIGHs (nested-script validation recursion, archive-collision preservation) remain fixed. |
cb3ec9b to
8e0d8c6
Compare
|
Addressed in HIGH — aliased network import bypasses egress detection ( |
8e0d8c6 to
9725b9e
Compare
|
Addressed in the latest push: HIGH — re-stage race on the slug-keyed Approve ( |
2b740d2 to
dbb0bbc
Compare
|
Addressed in HIGH — unredacted metadata via pending API ( HIGH — silent redaction failure on approve ( HIGH — incomplete sensitive-path denylist ( MEDIUM — approve could evict its own skill ( MEDIUM — nested scripts not executable ( MEDIUM — Approve before review ( Regression tests added for each. The remaining pass-2/3 MEDIUMs (autonomous lifecycle trigger, dashboard fallback consolidator wiring, unwired dedupe) are being triaged with the author. |
dbb0bbc to
b9f356e
Compare
|
Addressed the remaining MEDIUMs in MEDIUM — autonomous lifecycle ( MEDIUM — dashboard fallback consolidator ( MEDIUM — unwired dedupe judge ( Tests: |
b9f356e to
e9958b2
Compare
|
Addressed in HIGH — approve-time TOCTOU ( MEDIUM — dormant MEDIUM — indirect dangerous attribute ( Regression tests: failed-approve restores the candidate to pending; aliased-attribute rejection. Local gate green (flake8, mypy, 229 skill/history/config tests, config-baseline). |
|
Disposition on reviewed SHA
Local gate green (flake8/mypy + skill suites). This round the fail-closed |
|
Disposition on reviewed SHA
The prior write-side validator-denylist finding (skills_script_validator.py:145) is not re-raised on this SHA — the rebuttal (human-approval gate; denylist ≠ allowlist; blanket write-ban is disproportionate) stands. Local gate green (flake8/mypy + skill suites). |
|
/ai-review override gpt aa75d81: mandatory human approval plus approve-time re-validation, redaction, symlink/allowlist checks of the candidate's CURRENT bytes is the operative control; the requested digest-binding + atomic-quarantine machinery was deliberately reverted earlier as disproportionate over-engineering for a human-approval-gated feature, and two independent local mirror reviews (codex-review.yml and claude-review.yml + AUTOSDE contracts) found no blocking issue on this diff. |
Human judgment recorded@iamwhatever marked the gpt AI finding as false positive, not applicable, or explicitly accepted for
This decision applies only to this commit. A new push requires a new judgment. |
|
Disposition on reviewed SHA
Also in this push (feature default change): |
|
Disposition on reviewed SHA
The candidate-integrity class (meta unlink, meta move-restore, redaction restore) is now closed comprehensively: no approval-abort path mutates or strands the pending candidate. Local gate green (flake8/mypy + skill suites). |
|
Disposition on reviewed SHA
The candidate-integrity class is now closed on all paths. The only outstanding item is the structural fs/env read-ban in the validator (validator:72), rebutted across prior SHAs as disproportionate for a human-approval-gated, opt-in feature. |
1 similar comment
|
Disposition on reviewed SHA
The candidate-integrity class is now closed on all paths. The only outstanding item is the structural fs/env read-ban in the validator (validator:72), rebutted across prior SHAs as disproportionate for a human-approval-gated, opt-in feature. |
|
Disposition on reviewed SHA
Grounded in governance: the secret-getter gap maps to the documented anti-pattern of exposing secrets to a broader audience (a generated |
|
Disposition on reviewed SHA
|
|
Disposition on reviewed SHA
Local gate green: posture test + skill suites (109 total) pass; isort/flake8/mypy clean. |
|
Disposition on reviewed SHA
Local gate green: backend flake8/mypy + skill/posture/baseline suites, and frontend |
|
Disposition on reviewed SHA
Grounded in governance (SAX-01 Outcome 3 DLP / egress-control: control all egress channels, not just HTTP, to prevent covert exfiltration). Local gate green: flake8/mypy + validator suite. |
…e + scripts + crystallize)
|
Disposition on reviewed SHA
Local gate green (history/dedupe/posture suites + |
|
/ai-review override gpt 6ff260d: Mandatory human approval of every candidate and script is the operative control (generation is opt-in / off by default); the residual findings are unbounded defense-in-depth on a human-gated path — the validator denylist is complete-as-you-name-primitives (never an allowlist), and crystallize's direct-write is deferred to the code-path staging follow-up while stage_skill_candidate already allocates unique slugs — and the set_model model-bleed was fixed in this SHA. |
|
AI-review override not recorded: |
|
/ai-review override fable 6839bf7: Opus has no findings, and new run timed out for 2 times. Since all GPT findings are solved, override |
|
AI-review override not recorded: |
Human judgment recorded@iamwhatever marked the fable AI finding as false positive, not applicable, or explicitly accepted for
This decision applies only to this commit. A new push requires a new judgment. |
Open PR relationship auditThis is a consolidated, point-in-time code-level audit note. It compares complete merge-base diffs and current/merged code; it does not treat a shared topic as duplication or partial coverage as completion. Relationship findings
No PR, Issue, label, branch, or review state was changed by the relationship-note portion of this audit. |
Summary
Reworks auto-skill generation into a safe, opt-in, staged pipeline, informed by a code-level review of the mature sibling project (NousResearch/hermes-agent). Generation is off by default — enable it in Settings → Skills (or
kirocrew config set skills.auto_create_from_sessions true). When on, nothing goes live unattended — candidates are staged for human approval, deduped, bounded, and (when deterministic) can ship a validated Python script.Pipeline: detect (during consolidation) → generate → metadata dedupe → pending queue → human approval → live → archive-if-unused.
Phases (each an isolated commit)
active→stale→archivedby inactivity) with pin + cron-referenced exemptions and a never-used grace floor; max-N cap as a backstop; archives are recoverable (restore_auto_skill) — the evictor never hard-deletes. Embedding-free metadata dedupe (skills_dedupe.py): one injectable judge call over all generated skills. Dot-dirs (.archive/,.pending/) pruned from discovery. NewSkillsConfigfields.stage/list/get/approve/dismiss/prune; approve marks scripts executable). Consolidator routes new skills to the queue whenapproval_required(default true);auto_create_from_sessionsdefaults false (opt-in). Enable via the new Settings → Skills toggle (or CLI). Dashboard API (GET /api/skills/-/pending,.../approve,.../dismiss,POST /api/skills/-/pin) + a self-contained Pending review panel in the Skills tab, and a Settings → Skills panel with the auto-generate + require-approval toggles.scripts[](Python-only, Windows-portable). Static validator (skills_script_validator.py) blocks destructive commands, credential/sensitive-path access (incl. secret env-var getters), network egress (HTTP clients, sockets,asynciostream openers,webbrowser), oversize, non-Python, syntax errors — runs even on the auto-approve path, and scripts are re-validated after redaction. Script-bearing candidates always require approval; dangerous scripts are dropped while the prose skill still stages.$crystallizeon-demand skill. Builtin skill to capture the current session (incl.[Subagent completion event]output) into a staged candidate, with cross-source dedup.Design divergences from Hermes (deliberate, KiroCrew-specific)
Safety / integrity hardening
SKILL.md,.meta.json,scripts/dir), re-validation + redaction of the candidate's current bytes, and restore-on-abort on every failure path so a rejected candidate is never left partially-redacted or stranded.prune_pendingages by filesystem mtime (not LLM-supplied timestamps),set_pinnedusesatomic_write, and same-slug staging allocates a unique sibling slug instead of dropping a distinct candidate.skills.pyis a registeredsecurity_postureredaction sink.Testing
test_skill_lifecycle,test_skill_dedupe,test_skill_pending,test_skill_pending_api,test_skill_script_validator,test_crystallize_skill) plustest_security_posture,test_config_baseline,test_historyauto-skill classes, andtest_config_loaderall pass;isort/flake8/mypyclean on changed source.tsc -bclean;SkillsTab+SkillsPanel.settingsvitest pass;npm run buildOK.Config (new / changed defaults)
auto_create_from_sessions→ false (opt-in; enable in Settings → Skills),approval_required=true,max_auto_skills=100,stale_after_days=30,archive_after_days=90,pending_ttl_days=30,generate_scripts=true,judge_model=claude-haiku-4.5. Bothskills.auto_create_from_sessionsandskills.approval_requiredare on thePATCH /api/config/kirocrewallowlist so the Settings toggle can set them.Notes / follow-ups
find_similarfallback. The judge runs on the shared background lite model (no per-turn model switch).$crystallizethrough the code-path staging (skill_stage) rather than prose-guided direct writes; and a per-skill pin button in the Skills tab (thepinSkillAPI + lifecycle exemption already exist).