Skip to content

fix(bin): treat a never-asked external-imports prompt as not a decline - #4

Merged
rub-a-dub-dub merged 3 commits into
mainfrom
fm/firstmate-claude-trust-never-asked-reads-as-declined
Sep 19, 2026
Merged

rub-a-dub-dub merged 3 commits into
mainfrom
fm/firstmate-claude-trust-never-asked-reads-as-declined

Conversation

@rub-a-dub-dub

@rub-a-dub-dub rub-a-dub-dub commented Sep 19, 2026 •

Copy link
Copy Markdown
Owner

Intent

Firstmate's own defect, found and filed by firstmate on 2026-09-16 while two of the captain's tasks were stranded by it.

WHAT BREAKS: firstmate refuses to launch any Claude worker for a project whose Claude config records the external-imports prompt as not approved - but it cannot tell "the captain declined" from "the captain was never asked". Those are different, and the difference is recorded.

WHAT IT COST, concretely: on 2026-09-17 two finished firstmate tasks could not be moved to Claude for an entire evening while their other runtime was out of allowance. The captain could not clear it by answering the prompt either, because that project's own instructions never trigger the dialog - his words, "It never ased me the second q". He eventually had to edit his own config by hand. The gate was unclearable by the very action it implicitly demanded.

What Changed

  • bin/fm-claude-trust.sh now requires hasClaudeMdExternalIncludesApproved===false and hasClaudeMdExternalIncludesWarningShown===true before treating a project entry as an explicit "No, disable" answer. approved===false on its own is Claude Code's pre-dialog default, so a never-asked project now falls through to the normal untouched-imports path and registers trust instead of refusing the whole registration.
  • Script comments — the top-of-file consent-gating block and the declinedExternalImports comment — were rewritten to record the two-flag contract and the claude 2.1.278 disassembly evidence that every post-default write of the approved flag also sets warningShown===true.
  • tests/fm-claude-trust.test.sh adds two cases covering the never-asked shapes (warningShown explicitly false, and absent entirely): both must exit 0, land trust without import consent on the worktree and project-root entries, and preserve the project entry's unrelated settings. The existing decline test's comment was updated to state the pairing it relies on. .agents/skills/harness-adapters/references/harness/claude.md was synced to the same rule.

Risk Assessment

✅ Low: The functional change is a single two-line narrowing of one predicate, its vendor-behavior premises were independently confirmed against the installed claude binary, the consent-safety invariant is preserved by a separate approved===true check, and two new behavioral regression tests cover both never-asked shapes.

CI

This PR shipped without a CI gate. GitHub Actions has never been activated on this fork (rub-a-dub-dub/firstmate), so no check run was ever registered here - gh pr view reports "0 passed, 0 failed — this PR has no CI checks configured". Every step through Push (intent, rebase, review, test, document, lint, push) completed and passed; the pipeline's CI step was cancelled after it waited for checks that can never arrive on this fork. This is a known, already-filed gap unrelated to this change - two other PRs shipped ungated today for the same reason.

Testing

Ran the targeted claude-trust suite and the harness-adapter reference test (both pass), then produced the real evidence by driving bin/fm-spawn.sh's Claude launch path over four project-config shapes against both the base commit and the fixed commit: before the fix a never-asked project entry is refused as a decline and no worker is launched (the captain's stranded-task symptom), after the fix the worker launches with its brief while the project entry's import flags stay untouched, and a genuine decline plus a prior explicit approval both still behave as before. One demo run initially failed on an unrelated leftover /tmp/fm-<id> task temp root from an earlier run; re-running with run-unique task ids was clean and reproducible. The edited harness reference doc is agent-facing prose with no rendered end-user surface, so no visual artifact applies to it. Temporary trees and task temp roots created during testing were removed and the worktree is clean.

Evidence: CLI transcript: fm-spawn claude launch before vs after the fix, four consent shapes

Source: CLI transcript: fm-spawn claude launch before vs after the fix, four consent shapes

Firstmate: "never asked" must not read as "declined"
====================================================
Each block below drives the real bin/fm-spawn.sh claude launch path (tmux and
claude are the test suite's standard fakes, so "worker pane received" is the
exact command a worker pane would be sent). $TMP is the throwaway fixture root,
$FM_ROOT the firstmate checkout under test. Generated by
never-asked-spawn-demo.sh in this directory; task ids are run-unique.

Reading it: exit 0 + a launch command = the Claude worker started on the task.
exit 1 + "no worker was launched" = the captain's task is stranded.


=== BEFORE FIX (base 6f4c112) | project NEVER ASKED about external imports (approved=false, warningShown=false) ===
captain$ cat ~/.claude.json  # project entry for project
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":false,"allowedTools":["Read"]}
captain$ fm spawn never-asked --harness claude   # launch a Claude worker on the task
  warning: $TMP/never-asked/home/data/never-asked-r1/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  error: project entry for $TMP/never-asked/project in $TMP/never-asked/claude-config/.claude.json already declined external CLAUDE.md imports; refusing to override that consent
  error: refusing to pre-register Claude trust: could not record trust for '$TMP/never-asked/wt' and project '$TMP/never-asked/project' in '$TMP/never-asked/claude-config/.claude.json'
  error: could not pre-register Claude workspace trust for $TMP/never-asked/wt; refusing to launch a claude worker that would wedge on the trust dialog; inspect window firstmate:fm-never-asked-r1
  [exit 1]
worker pane received: (nothing - no worker was launched)
project entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":false,"allowedTools":["Read"]}
worktree entry after the spawn:
  "(no entry)"

=== BEFORE FIX (base 6f4c112) | project NEVER ASKED, warningShown flag absent entirely ===
captain$ cat ~/.claude.json  # project entry for project
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false}
captain$ fm spawn never-asked-absent --harness claude   # launch a Claude worker on the task
  warning: $TMP/never-asked-absent/home/data/never-asked-absent-r1/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  error: project entry for $TMP/never-asked-absent/project in $TMP/never-asked-absent/claude-config/.claude.json already declined external CLAUDE.md imports; refusing to override that consent
  error: refusing to pre-register Claude trust: could not record trust for '$TMP/never-asked-absent/wt' and project '$TMP/never-asked-absent/project' in '$TMP/never-asked-absent/claude-config/.claude.json'
  error: could not pre-register Claude workspace trust for $TMP/never-asked-absent/wt; refusing to launch a claude worker that would wedge on the trust dialog; inspect window firstmate:fm-never-asked-absent-r1
  [exit 1]
worker pane received: (nothing - no worker was launched)
project entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false}
worktree entry after the spawn:
  "(no entry)"

=== BEFORE FIX (base 6f4c112) | captain GENUINELY DECLINED the import dialog (approved=false, warningShown=true) ===
captain$ cat ~/.claude.json  # project entry for project
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":true}
captain$ fm spawn declined --harness claude   # launch a Claude worker on the task
  warning: $TMP/declined/home/data/declined-r1/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  error: project entry for $TMP/declined/project in $TMP/declined/claude-config/.claude.json already declined external CLAUDE.md imports; refusing to override that consent
  error: refusing to pre-register Claude trust: could not record trust for '$TMP/declined/wt' and project '$TMP/declined/project' in '$TMP/declined/claude-config/.claude.json'
  error: could not pre-register Claude workspace trust for $TMP/declined/wt; refusing to launch a claude worker that would wedge on the trust dialog; inspect window firstmate:fm-declined-r1
  [exit 1]
worker pane received: (nothing - no worker was launched)
project entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":true}
worktree entry after the spawn:
  "(no entry)"

=== BEFORE FIX (base 6f4c112) | captain previously ANSWERED YES to the import dialog ===
captain$ cat ~/.claude.json  # project entry for project
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":true,"hasClaudeMdExternalIncludesWarningShown":true}
captain$ fm spawn approved --harness claude   # launch a Claude worker on the task
  warning: $TMP/approved/home/data/approved-r1/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  spawned approved-r1 harness=claude kind=ship mode=no-mistakes yolo=off window=firstmate:fm-approved-r1 worktree=$TMP/approved/wt
  [exit 0]
worker pane received:
  CLAUDE_CONFIG_DIR='$TMP/approved/claude-config' env -u CURSOR_AGENT -u CURSOR_INVOKED_AS -u GEMINI_CLI CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false CLAUDE_CODE_SEND_FEEDBACK=0 claude --dangerously-skip-permissions --settings '{"feedbackDrafts":"off","attribution":{"commit":"","pr":"","sessionUrl":false}}' "$('$FM_ROOT/bin/fm-operational-input.sh' encode launch-brief < '$TMP/approved/home/data/approved-r1/launch-brief.md')"
project entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":true,"hasClaudeMdExternalIncludesWarningShown":true}
worktree entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":true,"hasClaudeMdExternalIncludesWarningShown":true}

=== AFTER FIX (2ccd942) | project NEVER ASKED about external imports (approved=false, warningShown=false) ===
captain$ cat ~/.claude.json  # project entry for project
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":false,"allowedTools":["Read"]}
captain$ fm spawn never-asked --harness claude   # launch a Claude worker on the task
  warning: $TMP/never-asked/home/data/never-asked-r2/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  spawned never-asked-r2 harness=claude kind=ship mode=no-mistakes yolo=off window=firstmate:fm-never-asked-r2 worktree=$TMP/never-asked/wt
  [exit 0]
worker pane received:
  CLAUDE_CONFIG_DIR='$TMP/never-asked/claude-config' env -u CURSOR_AGENT -u CURSOR_INVOKED_AS -u GEMINI_CLI CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false CLAUDE_CODE_SEND_FEEDBACK=0 claude --dangerously-skip-permissions --settings '{"feedbackDrafts":"off","attribution":{"commit":"","pr":"","sessionUrl":false}}' "$('$FM_ROOT/bin/fm-operational-input.sh' encode launch-brief < '$TMP/never-asked/home/data/never-asked-r2/launch-brief.md')"
project entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":false,"allowedTools":["Read"]}
worktree entry after the spawn:
  {"hasTrustDialogAccepted":true}

=== AFTER FIX (2ccd942) | project NEVER ASKED, warningShown flag absent entirely ===
captain$ cat ~/.claude.json  # project entry for project
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false}
captain$ fm spawn never-asked-absent --harness claude   # launch a Claude worker on the task
  warning: $TMP/never-asked-absent/home/data/never-asked-absent-r2/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  spawned never-asked-absent-r2 harness=claude kind=ship mode=no-mistakes yolo=off window=firstmate:fm-never-asked-absent-r2 worktree=$TMP/never-asked-absent/wt
  [exit 0]
worker pane received:
  CLAUDE_CONFIG_DIR='$TMP/never-asked-absent/claude-config' env -u CURSOR_AGENT -u CURSOR_INVOKED_AS -u GEMINI_CLI CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false CLAUDE_CODE_SEND_FEEDBACK=0 claude --dangerously-skip-permissions --settings '{"feedbackDrafts":"off","attribution":{"commit":"","pr":"","sessionUrl":false}}' "$('$FM_ROOT/bin/fm-operational-input.sh' encode launch-brief < '$TMP/never-asked-absent/home/data/never-asked-absent-r2/launch-brief.md')"
project entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false}
worktree entry after the spawn:
  {"hasTrustDialogAccepted":true}

=== AFTER FIX (2ccd942) | captain GENUINELY DECLINED the import dialog (approved=false, warningShown=true) ===
captain$ cat ~/.claude.json  # project entry for project
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":true}
captain$ fm spawn declined --harness claude   # launch a Claude worker on the task
  warning: $TMP/declined/home/data/declined-r2/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  error: project entry for $TMP/declined/project in $TMP/declined/claude-config/.claude.json already declined external CLAUDE.md imports; refusing to override that consent
  error: refusing to pre-register Claude trust: could not record trust for '$TMP/declined/wt' and project '$TMP/declined/project' in '$TMP/declined/claude-config/.claude.json'
  error: could not pre-register Claude workspace trust for $TMP/declined/wt; refusing to launch a claude worker that would wedge on the trust dialog; inspect window firstmate:fm-declined-r2
  [exit 1]
worker pane received: (nothing - no worker was launched)
project entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":true}
worktree entry after the spawn:
  "(no entry)"

=== AFTER FIX (2ccd942) | captain previously ANSWERED YES to the import dialog ===
captain$ cat ~/.claude.json  # project entry for project
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":true,"hasClaudeMdExternalIncludesWarningShown":true}
captain$ fm spawn approved --harness claude   # launch a Claude worker on the task
  warning: $TMP/approved/home/data/approved-r2/launch-brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  spawned approved-r2 harness=claude kind=ship mode=no-mistakes yolo=off window=firstmate:fm-approved-r2 worktree=$TMP/approved/wt
  [exit 0]
worker pane received:
  CLAUDE_CONFIG_DIR='$TMP/approved/claude-config' env -u CURSOR_AGENT -u CURSOR_INVOKED_AS -u GEMINI_CLI CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false CLAUDE_CODE_SEND_FEEDBACK=0 claude --dangerously-skip-permissions --settings '{"feedbackDrafts":"off","attribution":{"commit":"","pr":"","sessionUrl":false}}' "$('$FM_ROOT/bin/fm-operational-input.sh' encode launch-brief < '$TMP/approved/home/data/approved-r2/launch-brief.md')"
project entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":true,"hasClaudeMdExternalIncludesWarningShown":true}
worktree entry after the spawn:
  {"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":true,"hasClaudeMdExternalIncludesWarningShown":true}
Evidence: Reproduction script that generated the transcript

Source: Reproduction script that generated the transcript

#!/usr/bin/env bash
# End-to-end demo of the never-asked-vs-declined fix, driven through the real
# bin/fm-spawn.sh claude launch path (tmux and claude are the suite's standard
# fakes, so the launch command itself is what a worker pane would receive).
#
# usage: never-asked-spawn-demo.sh <repo-tree> <label>
set -u
TREE=$1
LABEL=$2
# fm-spawn creates a per-task temp root /tmp/fm-<id> that outlives the run, so
# every scenario gets a run-unique task id rather than colliding with a prior
# demo's leftovers.
RUN=${3:-$$}

# shellcheck source=/dev/null
. "$TREE/tests/fixtures.sh"
TMP_ROOT=$(fm_test_tmproot fm-neverasked-demo)

banner() { printf '\n=== %s ===\n' "$1"; }

show_store() {  # <store> <key>
  node -e '
    const fs=require("node:fs");
    const j=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));
    const e=(j.projects||{})[process.argv[2]];
    console.log(JSON.stringify(e===undefined?"(no entry)":e));
  ' "$1" "$2"
}

scenario() {  # <name> <headline> <project-entry-json>
  local name=$1 headline=$2 entry=$3 id
  local case_dir home proj wt config fakebin out rc
  id="$name-$RUN"
  case_dir="$TMP_ROOT/$name"
  home="$case_dir/home"; proj="$case_dir/project"; wt="$case_dir/wt"
  config="$case_dir/claude-config"
  mkdir -p "$config"
  fakebin=$(fm_test_make_spawn_fakebin "$case_dir/fake" claude)
  fm_test_spawn_home "$home" claude
  fm_git_worktree "$proj" "$wt" "wt-$name"
  fm_test_spawn_brief "$home" "$id" "finish the stranded task"
  printf '{"hasCompletedOnboarding":true,"projects":{"%s":%s}}\n' "$proj" "$entry" \
    > "$config/.claude.json"

  banner "$LABEL | $headline"
  printf 'captain$ cat ~/.claude.json  # project entry for %s\n' "$(basename "$proj")"
  printf '  %s\n' "$(show_store "$config/.claude.json" "$proj")"
  printf 'captain$ fm spawn %s --harness claude   # launch a Claude worker on the task\n' "$name"
  out=$(FM_TEST_CLAUDE_CONFIG_DIR="$config" FM_FAKE_LAUNCH_LOG="$case_dir/launch.log" \
    fm_test_run_spawn "$home" "$wt" "$fakebin" "$id" "$proj" claude \
    --mode no-mistakes --yolo off)
  rc=$?
  printf '%s\n' "$out" | sed 's/^/  /'
  printf '  [exit %s]\n' "$rc"
  if [ -s "$case_dir/launch.log" ]; then
    printf 'worker pane received:\n'
    sed 's/^/  /' "$case_dir/launch.log"
  else
    printf 'worker pane received: (nothing - no worker was launched)\n'
  fi
  rm -rf "/tmp/fm-$id"
  printf 'project entry after the spawn:\n  %s\n' "$(show_store "$config/.claude.json" "$proj")"
  printf 'worktree entry after the spawn:\n  %s\n' "$(show_store "$config/.claude.json" "$wt")"
}

scenario never-asked \
  'project NEVER ASKED about external imports (approved=false, warningShown=false)' \
  '{"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":false,"allowedTools":["Read"]}'

scenario never-asked-absent \
  'project NEVER ASKED, warningShown flag absent entirely' \
  '{"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false}'

scenario declined \
  'captain GENUINELY DECLINED the import dialog (approved=false, warningShown=true)' \
  '{"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":true}'

scenario approved \
  'captain previously ANSWERED YES to the import dialog' \
  '{"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":true,"hasClaudeMdExternalIncludesWarningShown":true}'
Evidence: Key contrast (never-asked project entry)
=== BEFORE FIX (base 6f4c112) | project NEVER ASKED about external imports (approved=false, warningShown=false) ===
captain$ cat ~/.claude.json # project entry for project
{"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":false,"allowedTools":["Read"]}
captain$ fm spawn never-asked --harness claude
error: project entry ... already declined external CLAUDE.md imports; refusing to override that consent
error: could not pre-register Claude workspace trust ...; refusing to launch a claude worker that would wedge on the trust dialog
[exit 1]
worker pane received: (nothing - no worker was launched)

=== AFTER FIX (2ccd942) | project NEVER ASKED about external imports (approved=false, warningShown=false) ===
captain$ fm spawn never-asked --harness claude
spawned never-asked-r2 harness=claude kind=ship mode=no-mistakes yolo=off window=firstmate:fm-never-asked-r2
[exit 0]
worker pane received:
CLAUDE_CONFIG_DIR='$TMP/never-asked/claude-config' ... claude --dangerously-skip-permissions --settings '{...}' "$('$FM_ROOT/bin/fm-operational-input.sh' encode launch-brief < '$TMP/.../launch-brief.md')"
project entry after the spawn:
{"hasTrustDialogAccepted":true,"hasClaudeMdExternalIncludesApproved":false,"hasClaudeMdExternalIncludesWarningShown":false,"allowedTools":["Read"]} # unchanged - no consent manufactured
worktree entry after the spawn:
{"hasTrustDialogAccepted":true}

=== AFTER FIX (2ccd942) | captain GENUINELY DECLINED (approved=false, warningShown=true) ===
error: ... already declined external CLAUDE.md imports; refusing to override that consent
[exit 1]
worker pane received: (nothing - no worker was launched)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • ⚠️ .agents/skills/harness-adapters/references/harness/claude.md:28 - The agent-facing harness reference still states the pre-fix decline rule and now contradicts the code. Line 28 reads "When the project entry instead already carries an explicit decline (===false), the whole registration refuses - including the trust flag", and line 33 repeats it as a diagnostic ("A visible trust dialog means pre-registration did not take effect (or the project entry already carries an explicit decline)"). After bin/fm-claude-trust.sh:473-474, hasClaudeMdExternalIncludesApproved===false alone no longer refuses; only that value paired with hasClaudeMdExternalIncludesWarningShown===true does. Concrete misdiagnosis path: AGENTS.md:211 mandates loading harness-adapters "before trust handling", so an agent inspecting a store whose project entry holds {&#34;hasClaudeMdExternalIncludesApproved&#34;:false,&#34;hasClaudeMdExternalIncludesWarningShown&#34;:false} after a wedged pane will follow line 28 and conclude the registration refused on a decline, when the script in fact registered trust successfully and the pane is wedged on the separate external-imports dialog - the exact two states this change exists to tell apart. Remedy is a mechanical sync of those two sentences to name the approved===false + warningShown===true pairing as the decline; it corrects what the change already does rather than extending it.

🔧 Fix: sync claude harness reference with never-asked decline rule
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-claude-trust.test.sh (32 checks, including the two new never-asked cases)
  • bash tests/fm-harness-adapter-references.test.sh (routing artifact + edited harness/claude.md reference reachable)
  • Manual end-to-end spawn demo through bin/fm-spawn.sh (suite's standard tmux/claude fakes) over four config shapes — never-asked, never-asked with warningShown absent, genuine decline, prior approval — run against both the base tree (git archive 6f4c112) and the worktree under test: never-asked-spawn-demo.sh &lt;tree&gt; &lt;label&gt; &lt;run-tag&gt;
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…line

hasClaudeMdExternalIncludesApproved===false is also Claude Code's own
pre-dialog default, not only the result of an explicit "No, disable"
answer, so a project entry that was never asked read as a permanent
decline and blocked every Claude worker for that project. Disassembly
of the installed claude binary confirms hasClaudeMdExternalIncludesWarningShown
is set true only when the dialog actually rendered and was answered,
so that flag is what now gates the decline check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant