Repository navigation
feat: select project skills for worker launches - #49
Merged
Merged
Conversation
Every ship and scout launch and relaunch now runs bin/fm-skill-pick.sh once its task copy exists. It judges the copy's .agents/skills and .claude/skills (an earlier folder wins a duplicate name) and adds the one picked skill to the launch instructions as a skill to read in full and follow, after the existing mandatory triggers. When nothing fits or the picker cannot run, the launch continues and the instructions and task record say why. The recipe is the TypeSafe skill-suggestion cookbook (rank the whole roster with three need gates, then rerank the top three with 700-character excerpts and one fits noul each; 0.30 and 0.30 thresholds), with the cookbook's question texts verbatim. It runs on the vendored hyper-jev starter client, imported unchanged from .agents/skills/hyper-jev/templates/starter/src/core/. This replaces bin/fm-skill-suggest.sh, bin/fm-skill-catalog.jq and their test, which ran only when a brief carried a "Skill selection input" section. The brief text sent is the text dispatch resolution may send: fm_typesafe_brief_task moves from bin/fm-dispatch-resolve.sh into bin/fm-typesafe-lib.sh and is shared, and every string either request can carry passes the dispatch-never-send check first. Keys come from the home .env through fm_typesafe_key and the new fm_openrouter_key, and reach Node on stdin. System assessment Dependency map: - bin/fm-spawn.sh -> bin/fm-skill-pick.sh (bounded by fm_run_timed at 30 s, process-group kill) -> bin/fm-typesafe-lib.sh (brief text, never-send, keys) and bin/fm-skill-pick.mjs -> vendored hyper-jev client -> TypeSafe direct, then OpenRouter on a failed direct call. - bin/fm-dispatch-resolve.sh -> fm_typesafe_brief_task (moved, unchanged behavior; tests/fm-dispatch-resolve.test.sh passes). - The launch section is written before the no-mistakes intent overlay, so it never becomes --intent text. - Runtime needs: node with .ts type stripping (Node 24+, as the vendored starter declares) and jq; without either the launch proceeds and records the reason. Blast radius: - Every ship and scout launch and relaunch gains one picker run and one "# Skill selection" section; secondmate charters are not touched. - No key: the picker stops after the key check (0.05 s), makes no network call, and records status unavailable; launch otherwise unchanged. - Hung or failing provider: each call is bounded at 10 s, the whole pick at 25 s inside the 30 s spawn bound. - The task record gains skill_selection=, skill_selection_reason= and skill_selection_picked=, owned and preserved across relaunch. Spawn latency: - Live, firstmate's 29 skills, synthetic task, TypeSafe direct: 0.90 s, 1.14 s, 1.50 s for the whole picker (jev-1.13.0, picked afk). - Offline, Vernant's real catalog: 245 skills in one Choice; request 1 is 48,689 bytes, request 2 is 3,903 bytes; 1.40 s local wall time at load average about 265 on 18 cores. Deviations from the examples: - bin/fm-skill-pick.mjs:169: a failed direct TypeSafe call is retried once through OpenRouter, which serves the rest of the pick; the starter picks one provider by key presence and never switches, and OpenRouter is the required fallback for a failed direct call. - bin/fm-typesafe-lib.sh:34: the OpenRouter key is read from the home .env only, never the ambient environment, where another project's key may live. - bin/fm-skill-pick.mjs:50-51: per-call timeoutMs 10 s and an overall 25 s signal, because the starter's 30 s default per call exceeds the spawn bound. - bin/fm-skill-pick.mjs:184-187: above 255 skills the Choice is split into which::N questions in the same request, as the cookbook advises; no skill is dropped. - bin/fm-skill-pick.mjs:72: SKILL.md frontmatter replaces the cookbook's prepared roster file; one description serves as description and description_full. - bin/fm-skill-pick.mjs:129: only Git-tracked SKILL.md files are sent, as before; other skills are listed by name as not judged. - bin/fm-skill-pick.sh:53: "read this skill in full and follow it" replaces the cookbook's "Ignore this if it does not fit". - The starter's default jev-latest replaces the cookbook's pinned jev-1.12.
…prerequisite skips
…selection metadata
…mentation ownership
…ck’s memory limit (exit 251, peak RSS 8,388,000 KiB). Removed redundant direct imports of fm-pr-lib.sh and fm-classify-lib.sh; fm-dod-lib.sh still loads both before use, preserving full source-aware analysis and launch behavior. Updated lint ownership documentation without changing CI limits or diagnostic rules. Verification: uncached full spawn lint passed with peak RSS 7,767,568 KiB on Darwin; the complete fm-skill-pick behavioral suite passed when run without concurrent heavy lint; pinned actionlint validated all three workflows. The broader lint regression suite and canonical partition exceeded local command deadlines. Linux address-space enforcement remains unverified locally because macOS cannot enforce that CI bound. Temporary verification files were removed
…fallback boundaries
MrGTV-love
force-pushed
the
fm/fm-worker-project-skill-picker
branch
from
October 8, 2026 11:36
0ce3d26 to
555f6d4
Compare
This was referenced Oct 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
workers should have the skill picker
after workers potentially ignoring DoS and CoC skills, they need it
Calling out the specific skill does not make sense. Firstmate needs to operate with skills. Otherwise, it is a free-for-all as Firstmate is focused on orchestration. The work that is done in the sessions is through skills.
When looking at the timeouts and harness issues, assess individual fixes, but also assess as a system with dependencies. We often fix one thing to break another. I want to fix without breaking. I want to fix without needing to fix again.
Context needed to read the ask (facts checked 2026-10-07):
defining-operational-solutionsandchain-of-custody, in Vernant's.agents/skills/(231 skills) and.claude/skills/(234 skills).bin/fm-skill-suggest.sh(Jev, model jev-1.13.0).bin/fm-spawn.sh(around line 3315) runs it only when a brief contains a# Skill selection inputsection; no worker brief in any Vernant lane home has that section, so it never runs for them..agents/skills, not the project's, and it caps the catalog at 128 skills (Vernant has more).openrouter is a fallback from directly using the typesafe api
is the skill-picker aligned with the example I shared or is it still the makeshift version created before?
don't rebuild it. use your memory which says to use the example and modify only if necessary
that is a lot easier than rebuilding. No slop
Context needed to read those words:
.agents/skills/hyper-jev(upstream https://github.com/disler/ten-levels-of-jev).bin/fm-skill-suggest.shwithbin/fm-skill-catalog.jq, an invented two-stage design with its own thresholds and a 128-skill cap.I asked for A already
Context needed to read those words (2026-10-07):
bin/fm-dispatch-resolve.shalready sends (the brief's task subsections), to TypeSafe direct first and to the OpenRouter fallback, and docs/configuration.md records that authorization without widening any other sending boundary.What Changed
Risk Assessment
Testing
The targeted picker and key-source suites, focused spawn-selection regression, and live CLI, privacy, catalog, runtime-guard, worker-delivery and failed-relaunch scenarios passed. Initial command limits and driver assertion issues were addressed with a longer picker run, focused runner checks and corrected captures. CLI transcripts, persisted state and rendered terminal evidence were preserved; disposable labs were removed. Authenticated picks and real AI skill adherence remain untested under the previously declined credential blocker.
bin/fm-skill-pick.sh --helpinvocation exited successfully.NODE_OPTIONS=--no-experimental-strip-typescauses the real vendored-client import to produce the supported runtime diagnostic.Evidence: Current live picker CLI and boundary transcripts
Evidence: Actual project roster with 261 eligible skills
~/.no-mistakes/evidence/01M4D34BGQE483Q5806J9GM9AX/current-worker-transcripts.html)~/.no-mistakes/evidence/01M4D34BGQE483Q5806J9GM9AX/live-worker-delivery.txt)Evidence: Actual failed doorbell relaunch transcript
Evidence: Retained undelivered selection metadata
~/.no-mistakes/evidence/01M4D34BGQE483Q5806J9GM9AX/changed-test-selection.txt)~/.no-mistakes/evidence/01M4D34BGQE483Q5806J9GM9AX/current-test-run-notes.json)Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
🔧 **Rebase** - 6 issues found → auto-fixed ✅
.agents/skills/operational-home-layout/SKILL.md- merge conflict rebasing onto origin/mainbin/fm-test-run.sh- merge conflict rebasing onto origin/mainbin/fm-typesafe-lib.sh- merge conflict rebasing onto origin/maindocs/configuration.md- merge conflict rebasing onto origin/maindocs/scripts.md- merge conflict rebasing onto origin/maintests/fm-skill-suggest.test.sh- merge conflict rebasing onto origin/main🔧 Fix applied.
✅ Re-checked - no issues remain.
🔧 **Review** - 1 issue found → auto-fixed (2) ✅
bin/fm-skill-pick.sh:3- The new CLI wrapper is committed with mode 100644, preventing the direct invocation advertised here and by the error-help command at bin/fm-skill-pick.sh:24. Followingbin/fm-skill-pick.sh --helptherefore produces a permission error rather than help. Worker launches and the new tests explicitly invoke Bash, so those paths bypass this defect. Commit the wrapper as executable (100755), matching the removed CLI.🔧 Fix applied.
1 warning still open:
bin/fm-test-run.sh:425- The new picker suite owns worker-launch and failed-relaunch regressions but is classified as standalone. When only bin/fm-spawn.sh changes, --changed selects backend-dispatch and pure-contract-unit at bin/fm-test-run.sh:1641-1644, so tests/fm-skill-pick.test.sh is omitted. This leaves the new picker invocation at bin/fm-spawn.sh:4650 and failed-delivery metadata correction at bin/fm-spawn.sh:1526 without their targeted regression coverage. Related test consumers are tests/fm-skill-pick.test.sh:450 (launch integration) and :929 (failed relaunch delivery); the picker-source mapping at bin/fm-test-run.sh:1527 already selects this suite correctly. Add an explicit fm-skill-pick.test.sh selection for spawn changes while retaining the existing family selections.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ No issues found.
bash tests/fm-skill-pick.test.sh && bash tests/fm-typesafe-key-source.test.sh: initially interrupted by the 300-second command deadline during the picker suite; the chained key-source suite did not start.bash tests/fm-skill-pick.test.sh: rerun with a 1200-second ceiling; passed in 507.47 seconds, including failed-delivery metadata and relaunch regressions.bash tests/fm-typesafe-key-source.test.sh: passed independently.test_changed_spawn_selects_picker_without_broadening_siblings: executed the existing focused runner regression; passed.python3 .fm-live-validation.py: drove the executable picker, a 301-skill project roster, privacy refusals, promoted legacy extraction, and real provider-failure fallback. The disposable driver was removed and preserved in the evidence directory.python3 .fm-live-workers.py: drove real ship/scout launches, scout relaunch, and unsupported raw-command delivery in isolated named Herdr labs. Corrected session-wrapper, terminal-wrapping, and relaunch-argument setup issues before obtaining passing results.Additional public-picker invocations exercised empty versus excluded catalogs, sanitized promoted outbound requests, missing-TypeSafe-key OpenRouter fallback, and primary-home key inheritance without a lane.envcopy.Captured actual terminal output, generated launch briefs, persisted metadata, and real outbound request bodies without credential values; rendered worker transcripts as HTML.Tore down all disposable Herdr sessions throughbin/fm-herdr-lab.sh, with passing default-fleet tripwires, and removed workspace fixtures and throwaway drivers. No source or permanent test changes were made.Live validation:⚠️ inconclusive - 13 of 14 scenarios driven live against the product
bin/fm-skill-pick.sh --helpinvocation exited successfully.NODE_OPTIONS=--no-experimental-strip-typescauses the real vendored-client import to produce the supported runtime diagnostic.bash tests/fm-skill-pick.test.sh && bash tests/fm-typesafe-key-source.test.sh— initial attempt reached the 300-second command limit during the picker suite, before the key-source command ran.bash tests/fm-skill-pick.test.sh— completed successfully with a longer command allowance.bash tests/fm-typesafe-key-source.test.sh— passed.bash tests/fm-test-run.test.sh— passed the spawn-selection regression before reaching the 600-second command limit in later checks.Executed onlytest_changed_spawn_selects_picker_without_broadening_siblingsfrom the existing runner contract test through a temporary harness — passed; harness removed.Drovebin/fm-test-run.sh --list --changed --base HEADagainst six isolated single-file changes, verifying picker selection for spawn only and preservation of existing family selections.Drove the executablebin/fm-skill-pick.shandnode bin/fm-skill-pick.mjs rosteragainst disposable catalogs, homes, privacy policies and actual TypeSafe/OpenRouter endpoints without transport mocks.Executedfm_typesafe_brief_taskfor a promoted legacy brief underumask 022, checking effective task text and owner-only output permissions.Ranpython3 .v/spawn.pyagainst actual private tmux and Treehouse instances; joined terminal captures verified ship and scout brief delivery after correcting a soft-wrapping assertion.Ranpython3 .v/failure.pyagainst an actual failed doorbell relaunch, verifying retained undelivered metadata.Exported current terminal transcripts as rendered HTML, stopped private tmux servers, and removed disposable homes, projects, pools and temporary test drivers.✅ **Document** - passed
✅ No issues found.
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ No issues found.
✅ **Push** - passed
✅ No issues found.
✅ No issues found.