"skill seeding: N of M" is logged as success for opencode members, which never read .claude/skills/ #393
Closed
opened 2026-09-10 02:51:59 +02:00 by ltms
·
2 comments
No Branch/Tag Specified
main
worker/fleetd-612-unita-87807e-1
worker/612-b3-mcpwirings-da2b58-3
worker/612-b2-cb185-176d3a-2
worker/612-b1-completion-457459-1
worker/612-agaps-73a926-2
worker/608-sleeps-3a64ff-3
worker/621-b4520b-1
worker/618-b83894-2
worker/fleetd-615-e05481-5
worker/lead-autocompact-5f1ab2-3
worker/fleetd-613-f85deb-3
worker/fleetd-608-flaky-nudge-test-d0c2d1-3
worker/lead-context-gauge-ad404f-1
worker/gauge-wiring-9158c1-4
worker/redeploy-slowstart-ead0e5-5
worker/charter-bytes-13668c-6
worker/rollover-outcome-291483-2
worker/589-f64303-2
worker/593-1a8025-5
worker/589-fcd2aa-1
worker/568-9fdaa2-3
worker/571-attempted-outcome-5739f7-2
worker/581-completionresolver-cas-sites-0542b7-6
worker/562-loop-health-wiring-test-99611c-5
worker/562-surface-loop-health-7df5cc-4
worker/575-waiter-cleanup-sites-62ad80-1
worker/572-answer-lock-release-46a9ae-5
worker/567-probe-channel-leak-a38fc5-6
worker/551-record-before-send-7cbf56-1
worker/561-listener-fanout-survives-a-throw-61d538-2
worker/555-redeploy-main-flow-seam-65c2f5-2
worker/556-injector-owns-registration-e027a5-1
worker/552-post-restart-mktemp-abort-bc2672-4
worker/553-onstatus-completion-leak-0da881-2
worker/550-shasum-linux-196132-1
worker/538-loop-dies-on-error-4a5eeb-6
worker/426-health-coverage-ef1fd4-4
worker/504-failed-reported-clean-3cfd66-3
worker/537-capturedlog-close-e4c437-2
worker/459-broken-link-targets-cadc17-5
worker/535-appender-leak-fe74c1-1
worker/512-part2-shutdown-detection-434701-9
worker/529-logger-level-sweep-2a5533-8
worker/528-drain-gate-call-site-5de83d-7
charter/forge-mcp-vs-token
worker/521-swap-guard-unpinned-28e931-5
worker/519-probe-test-harness-d25ab8-4
worker/525-logger-level-leak-1b4eb0-6
worker/518-fleetmcp-resolver-wiring-8ef96c-1
worker/512-drain-complete-line-7edd71-3
worker/517-abort-branch-and-jar-id-41b641-2
worker/500-9e52c9-3
worker/509-4912f4-2
worker/511-9a4b23-1
worker/493-479f45-2
worker/505-03f8b2-1
worker/492-followup-detect-unclear
worker/501-a31fa0-7
worker/498-451d1c-5
worker/494-1015ce-2
worker/492-209647-1
worker/489-001902-2
worker/480-relative-handover-path-906323-1
worker/480-b-handover-skill-45bf1f-5
worker/474-followup-source-pin-f54a55-17
worker/474-charter-check-on-reload-f54a55-17
worker/466-quarantine-repeatcount-report
worker/393-opencode-skill-seeding-71854b-13
worker/469-canonical-tool-names-2a472a-16
worker/466-quarantine-escalation-5ae9c1-15
worker/446-hot-exhausted-pattern-0af580-6
worker/464-charter-tool-name-guard-a85635-12
worker/463-listfleet-default-fails-open-f1c76c-11
worker/458-invariant-5-by-purpose-862f9a-10
worker/439-coordinator-row-gate-bc032a-8
worker/449-herdr-protocol-576015-4
worker/450-abstract-spawn-599e1c-5
worker/437-ack-refuses-177d91-1
worker/444-placement-window-feb56a-2
worker/440-helddurable-derived-d462d7-13
worker/425-rework-placement-resolve-c58ba1-9
worker/421-lead-peek-held-msgs-cdbad2-10
worker/435-fixed-policy-cap-fe11de-12
worker/422-gate-state-observability-9e79d6-11
worker/431-memberregistry-live-readers-cdbad2-10
worker/424-architect-slot-hot-038b41-7
worker/422-model-gate-spawn-c29f48-6
worker/425-default-profile-live-f55534-8
worker/415-coverage-wording-2cbf9c-5
worker/416-3ad1da-1
worker/418-588283-3
worker/deterministic-stamp-race-409-3cb7b6-10
worker/armed-reads-live-config-404-ed931f-9
worker/reply-peer-refusal-391-5a34bd-7
worker/models-allowlist-aa9e9b-3
worker/ttl-stamp-race-399-f1122f-8
worker/scrub-receipt-400-316b3e-5
worker/exhaustion-detection-395-105105-6
worker/scrub-abort-394-316b3e-5
fix/scrub-uid-abort
worker/task-scrub-517574-2
worker/t386-clock-bd5b78-4
worker/t384-scrub-813790-5
worker/t381-cc-748314-2
worker/t373-336973-2
worker/t365-3920c5-3
worker/t358-6e989b-1
worker/t355-8b321c-1
worker/fleetd-369-hermetic-git-tests-e8b19a-3
worker/fleetd-368-stale-lead-binding-f5682e-2
worker/fleetd-360-deploy-units-0d3793-1
worker/359-dead-lead-tabs-f1253b-4
worker/362-worktree-skills-c03e51-3
worker/361-coord-visibility-655144-1
362-plugin-visibility-and-drift
worker/errscan-bed2ca-2
worker/amqp-log-identity-bed2ca-2
worker/withdefaults-guard-561704
worker/sleepguard-82076d-1
worker/fd334-9ee1b6-5
worker/fd348-f1ab27-4
worker/fd335-a71c35-1
worker/fd342-174a17-2
worker/fd345-490d0f-3
worker/fleetd-337-5ec7d4-21
worker/fleetd-341-af5a6b-24
worker/fleetd-339-5ca0a2-23
worker/fleetd-338-83a4a1-22
worker/fleetd-333-281f46-18
worker/fleetd-329-11bdbb-16
worker/fleetd-330-2770fb-17
worker/fix-326-50506e-15
worker/fix-324-3e9bbf-14
worker/fix-323-b8287d-13
worker/fix-316b-bd0860-11
worker/fix-318-76ca36-9
worker/fix-317-486aec-8
worker/fix-315-ce47c5-6
worker/fix-307-275890-6
worker/fix-308-b4f664-7
worker/fix-309-ec3939-8
worker/fix-310-7a3974-9
worker/fix-302-52ad0e-9
worker/fix-298-ce1acb-8
worker/fix-297-66bd11-7
worker/fix-296-104622-6
worker/fix-293-bare-closetab-eb22b5-3
worker/fix-280-gone-ask-lapse-bca98e-2
worker/fix-290-reapidle-guard-coverage-9b0dd1-1
worker/fix-285-trust-seed-8f3565-10
worker/fix-284-backend-error-seat-85912c-11
worker/fix-282-chained-ask-e6d0bb-8
worker/fix-283-teardown-leaks-f40dfa-9
worker/fix-281-pin-handler-actions-4921ac-7
worker/audit-rendezvous-lifecycle-d072ae-2
worker/audit-health-placement-1a2476-6
worker/audit-teardown-exits-e207a5-3
worker/audit-launcher-asymmetry-27e370-4
worker/audit-rest-authz-6ca53c-5
worker/investigate-275-abandon-asking-fdef52-8
worker/fix-274-worktree-leak-b0095d-7
worker/fix-273-exhausted-pattern-9665b5-6
worker/fleetd-267-model-check-bd8068-1
worker/fleetd-131-archunit-18b834-7
worker/fleetd-266-sshagent-rename-a014ff-6
worker/fleetd-184-uid-claim-8e1f31-4
worker/fleetd-184-warn-b381ee-10
worker/fleetd-184-docs-be1d12-9
worker/fleetd-257-9bf010-7
worker/fleetd-103-23a113-6
worker/fleetd-247-342356-5
worker/fleetd-116-04dea8-4
worker/fleetd-252-a830e0-3
worker/fleetd-111-7e8673-9
worker/fleetd-155c-f8ef4b-8
worker/fleetd-176-b928ca-3
worker/fleetd-249-7a7878-2
worker/cb248-composition-root-b-9acdf7-15
worker/cb148-envrc-default-fa6c82-12
worker/cb201-unit5-wiring-6c12e6-8
worker/cb241-fallback-echo-1175e9-11
worker/cb149-trust-dialog-2392a5-9
worker/cb134-148-overlay-visible-c9b986-10
worker/cb234-session-id-keyed-04e1fc-1
worker/cb201-unit3-nudge-abdf5c-6
worker/cb201-unit2-policy-c1102c-5
worker/cb201-unit4-outcome-a13bfa-7
worker/cb201-unit1-classifier-91b9b1-4
worker/cb201-227-refine-831980-3
worker/cb175-model-readback-0f085f-1
worker/cb222-charter-tmpdir-17f013-1
worker/cb226-architect-slot-race-cd3aa8-3
worker/cb224-worktree-root-group-024523-2
worker/cb-123-role-demotion-c600f7-2
worker/cb-219-opencode-roots-1f677e-1
worker/cb214-claude-session-id-b9eab4-4
worker/cb213-zdotdir-wrong-process-dd6de4-3
worker/cb211-exhaustion-classification-9546e0-2
worker/cb137-ambiguous-task-4df3d8-4
worker/cb209-agentsessionid-4dfdb6-2
worker/cb185-hostenvnames-2692b5-3
worker/cb206-opencode-sqlite-128718-2
worker/cb185-worktree-group-fc0c99-1
worker/cb-137-ask-ticket-e7760c-2
worker/cb-172-broker-uri-d36ae4-4
worker/cb-175-model-readback-76ead6-3
worker/cb-161-pane-ancestry-293510-1
worker/cb-164-rebase-885863-8
worker/cb-164-empty-scrape-false-success-1a80af-3
fix/cb-197-ticket-ttl-from-completion
worker/cb-189-remote-url-coverage-4692f3-1
worker/cb-185-blockers-027756-4
worker/cb-192-gap-log-11b631-2
worker/cb-633-fix-5f4396-3
worker/cb185-router-d6436d-3
worker/cb185-router-routing-gaps-9e9d33-3
worker/cb185-paneids-992586-2
worker/cb-633-allow-list-union-ed374b-1
worker/cb-157-credential-in-remote-url-496e44-2
worker/cb-641-health-herdr-evidence-8f1f54-6
worker/cb-640-health-msg-evidence-99c9cd-1
worker/cb-642-fleets-status-skill-bbbc40-5
cb-634-ide-mcp
worker/lead-comms-wiring-c014b9-7
worker/lead-mailbox-c19577-6
worker/autocompact-window-82bc2f-5
worker/cb-634-probe-18056f-4
worker/cb635-broker-urienv
worker/cb-632-config-retry-8e0efa-7
lead/cb-622e-claude-md
lead/cb-622-followup
worker/cb-622a-165dff-1
lead/cb-622d-opencode-mount
worker/cb-622b-717c67-2
worker/cb-622c-ab7759-3
worker/cb-617b2-20ca4b-3
worker/cb-617a-5c2f4a-1
worker/cb596-4e49ef-3
worker/cb586-10500c-1
worker/cb-606-b9343a-25
worker/cb604-1445f8-24
worker/cb582-477374-21
worker/cb584-8c2281-22
worker/cb600-e6b9a9-20
worker/cb602-ce257f-19
worker/cb601-b42837-18
worker/cb598-6c7ba7-17
worker/cb599-740fe4-16
worker/cb597-282224-15
worker/cb590fix-185e9a-10
worker/cb528-recovery-race
worker/cb594-96bead-8
worker/cb590-916766-2
worker/cb527-997d99-3
worker/cb592-env-leak-3cbf9c-1
worker/cb588-async-ticket-nudge-3218f7-5
worker/cb578b-9dcb13-6
worker/cb581-d24826-5
worker/m2-u5-ef8c42-15
worker/cb578a-516499-2
worker/cb576-01a04b-17
worker/cb579-lead-tab-acba06-20
worker/cb580-terminal-health-ed6058-21
worker/cb577-f36fdc-18
worker/cb573b-3db06f-16
worker/cb568c-f36fdc-18
worker/cb568-drop-cause-c3ac1c
worker/cb575-cancelled-notification-c3ac1c
worker/m4-sol-a2cbec-3
worker/cb574-async-ask-c3ac1c
worker/cb573-health-model-8ca857-14
worker/cb572-unknown-target-7f2e35-13
worker/u4-700706-9
worker/u3-b9fcb6-6
worker/u2-ef5b68-4
worker/u1-469dce-1-clean
worker/u1-469dce-1
worker/cb-564-health-events-70cf7e-2
worker/cb-565-recycle-drops-role-98e58f-3
worker/cb-563-missing-reply-df2866-1
worker/cb-562-readiness-gate-silent-6c23c9-3
worker/cb-560-architect-presence-da8155-1
worker/cb-561-architect-silent-off-a71cab-2
worker/cb-548-bind-architect-slot-fe1b8c-1
worker/parity-overlay-settings-5fb711-1
secrets-central-store
cb-559-hot-key-correction
cb-557-fleet-role-pools
worker/cb-553-maxload-explicit-spawn-305ee3-6
worker/cb-551-idle-lead-heartbeat-f1633c-1
worker/cb-544-drain-preserves-worktree-925fad-3
worker/cb-552-docs-sync-1cb9cf-4
worker/cb-548-rendezvous-guard-rebased
worker/cb-548-rendezvous-guard-116b53-10
worker/cb-548-authz-v2-586df6-8
worker/cb-548-authz-264363-5
salvage/cb-528b-codex-home
salvage/cb-528a-codex-launcher
CB-518-primary-flow
feature/peer-launcher-spi
cb-103-injector
v1.1.0
v1.0.0
Labels
Clear labels
blocked
needs-live-proof
ready-to-delegate
silent-default
Cannot start until something else lands. The body says what.
Merged and green, but never shown working on the running daemon. Not the same as done.
Scope, files and acceptance criteria are written. A worker can be briefed from the body alone.
A feature that compiles, passes tests, and ships turned off. Nine recurrences and counting.
No Label
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: fleet/fleetd#393
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The defect
memberSkills:(fleetd #362) copies skill folders into every provisioned worktree's.claude/skills/, and logs a success line:.claude/skills/is a Claude Code convention. An opencode member takes its instructions from its generated config, and the seeded skills are not in it:OpenCodeLauncherbuilds that array from exactly two sources — the charter at:450and the IDE rules at:479. There is no third entry, and there is noAGENTS.mdin the worktree. So for akind: opencodemember the seeding is a guaranteed no-op, reported as3 of 3.GitWorktrees.seedSkillsnever consults the member kind. Its only guard ismemberSkillsSourcebeing null or blank.Consequence
An opencode member's entire instruction set is
member-charter.md, which is one paragraph and is all about callingfleet_reply. It carries no role procedure, no "never merge", no "stage files explicitly" — the content the lead believes it delivered.This bites hardest where a lead follows the charter correctly. Line 1 of every brief is meant to be
Load the <name> skill., and fleetd #362 exists precisely because that line used to be a silent no-op. For opencode members it still is; the log line just changed.It is not host-specific. Any host running opencode members has it. On fleet01 all three worker slots — dev, reviewer and architect — are
kind: opencode, so no member on that host has ever read a role contract.Fix — either is acceptable, the second is honest on its own
SKILL.mdtoinstructions[]for opencode-kind launchers, so the same content reaches both kinds.Do 1 if the skills are meant to apply to every member, which the
memberSkills:docs imply. Do 2 regardless — a success line for work that cannot take effect is the failure shape this repo keeps paying for, and 1 without 2 leaves the log unable to tell a real seeding from a skipped one.Acceptance
memberSkills:configured can act on the seeded role procedure, or the log says clearly that it cannot.memberSkills:set. Today the seeding tests do not vary the member kind.memberSkills:documentation states which member kinds actually consume it.Found by the fleet01 lead. I had reported the same consequence — members with no role contract — via the wrong mechanism, looking in
kb/CLAUDE.mdandkb/.claude/skills/; they traced the real channel. Verified against the code and filed by the mac lead at their request.Correction to my own severity claim. I wrote that all three of fleet01's worker slots are
kind: opencode, so no member there has ever read a role contract. That is wrong. The fleet01 lead corrected it, and I then measured it in their config over ssh rather than taking it:Four profiles, two kinds.
localandopusareclaude-codeand do read the seeded skills. So "3 of 3, nobody ever" overstates it.The accurate framing, which is narrower but sharper
By slot count: 7 of 10 configured slots are on an opencode profile and cannot read a role contract.
By placement weight, which is what decides where a spawn actually lands, it is worse than the slot count suggests.
opusisweight: 0, so it is never auto-selected — it is the lead seat. That leavesgx100,xf80 andlocal10 competing:So about 95% of their auto-placed members land on a profile that cannot read a role contract, and the remaining 5% is a single
claude-codeprofile with the lowest weight in the file. The defect is real and the practical severity is high — but for the reason above, not the reason I gave.Why I am recording the correction rather than just editing the number
An overstated severity is the thing a reader discounts later, which is the fleet01 lead's point and it is right. "Nobody ever" invites someone to check one counter-example and dismiss the whole ticket. "95% by weight, and the exception is the lowest-weighted profile" survives that check.
Note also that this is a per-host number. It is measured on fleet01 on 2026-09-10 and it changes the moment anyone edits a
weight:. Re-measure with the awk overprofiles:above rather than quoting 95% later.Unchanged
The defect itself:
memberSkillsseeding reports success for members that structurally cannot read it. Their side is closed byfleet.charters, which is daemon-local and reaches opencode members throughinstructions[]— verified there with a throwaway spawn. The seeding path's false success report is still open here.Merged as
17052bb(merge commit), with a comment correction on top;mainis at5ba69c9. PR #471. Verified landed withgit merge-base --is-ancestor, against an unmerged control branch that reportedno.My own mutation battery, on the merge commit
Ran on tree
dcf8959, which is the merge's tree exactly. Fullmvn -B clean testper cell.CONTROL 0: three writers on
instructions[],putArraycount 0 (was 1),withArraycount 3. All three new combination tests present. Four assertions useassertEquals(List.of(...))— contents, not size.CONTROL 1, unmutated: 1618 tests, 0 failures, 0 errors, BUILD SUCCESS.
putArray— the survivor from the last mergeinstructionsArrayHoldsCharterThenSkillsThenIdeRulesInOrderputArrayaSeededSkillReachesTheOpencodeMembersInstructionsArray,aSkillFolderWithoutSkillMdIsNeverDeliveredAndTheLogNamesIt,instructionsArrayHoldsCharterThenSkillsThenIdeRulesInOrderputArrayM1r is the one that matters. On the previous merge that same mutation left 1603 tests green while silently deleting the charter entry from an opencode member's config. It is now caught by name.
M2r survived, and that is correct
Flipping the charter writer back to
putArrayleaves the suite green and always will. That writer runs first against an empty array, so there is no existing node forputArrayto replace and the two idioms are indistinguishable. No test can tell them apart. The worker measured this independently and said so plainly in their report rather than claiming a kill they did not have.The edit is still right — it removes an ordering constraint nobody wrote down — but it is a readability change with no test behind it, and that is not a gap anyone can close.
The comment above that line claimed otherwise, so I corrected it. It said the flip was "proven load-bearing" and named two tests as covering it. Neither does. A comment naming tests that do not cover the line is worse than no comment: the next person mutates it, sees green, and concludes the tests are broken. The corrected comment states what each cell actually measures. That is commit
5ba69c9, comments only — 0 non-comment lines changed in either direction, and 0 test files readOpenCodeLauncher.javaas source text (control: 11 test files do readFleetd.javathat way), so the battery numbers still describe what was pushed.A correction to the diagnosis, including my own repeat of it
fleet01 first said the missing test axis was the combination of writers — that a test with one writer active cannot tell
putArrayfromwithArray. They then revised that to a stronger claim: that nothing asserted the charter reaches an opencode member at all, and that this hole predated #393.I checked the stronger claim and it is false. M3 (deleting the charter writer) fails 6 tests, and 3 of them existed before #393:
writesRemoteMcpConfigAndCharterInstructionsWhenMcpUrlSetroleCharterWithoutMcpOrCustomProviderStillWritesAConfigaPinnedEndpointAndTheFleetMcpCoexistInOneConfigMeasured by reading
OpenCodeLauncherTest.javaat789b6a8, the commit before this work, with a control name that correctly returned 0. The charter reaching a member was already pinned.So the first diagnosis was the right one. The surviving mutation never deleted the charter write; it made a later writer replace the whole array. Every pre-existing test had exactly one writer active. The gap was never "is the charter delivered" — it was "are two writers ever active at the same time", which is the combination axis, and that is what the three new tests add.
Recording this because the stronger claim is the more quotable one, and it would have sent the next reader hunting for a hole that is not there.
What this does not do
Opencode has no equivalent of Claude Code's Skill tool. The content arrives as static system-prompt text from spawn and cannot be invoked by name. So this closes the delivery gap and cannot close the activation gap; that residue is opencode's design, not a fleetd limit. Worth stating so nobody later reads "skills work on opencode now" as more than it is.
Wiki Features entry "Bridge skills are seeded into every provisioned worktree" updated with the opencode half and both gotchas — wiki commit
14798b3.Beyond-scope findings from the worker, not fixed
Three log lines that claim more than they check. Recording them here so they are not lost; none is filed yet.
GitWorktrees.java:1005— "parity overlay: copied {} of {} candidates" logs success regardless of member kind or whether anything reads the copied files.HerdrPeerLauncher.java:1454— logs the ZDOTDIR scrub as applied without checking the member's login shell is zsh. A non-zsh member's scrub silently never runs.HerdrPeerLauncher.java:1578/1668— "member credentials: allowed {} of {}" counts names allowed into the pane env without checking whether the member's runtime reads that variable. "Allowed" is not "used".The worker also checked and cleared
HerdrPeerLauncher.java:317and:1892, which both name their limiting condition already.