Skip to content

ci: give @claude the workspace config through --add-dir - #7083

Merged
otavio merged 4 commits into
masterfrom
ci/pr-review-config-via-add-dir
Sep 12, 2026
Merged

ci: give @claude the workspace config through --add-dir#7083
otavio merged 4 commits into
masterfrom
ci/pr-review-config-via-add-dir

Conversation

@otavio

@otavio otavio commented Sep 12, 2026

Copy link
Copy Markdown
Member

Pareado com shellhub-io/claude#65 e shellhub-io/cloud#2554.

O bug

O claude.yml sincroniza a config e em seguida roda uma action que a apaga: .claude/ e CLAUDE.md da raiz do workspace são substituídos pelas cópias do branch base, e este repo não versiona nenhum dos dois. Todo @claude vinha rodando sem as rules, sem as skills e sem o CLAUDE.md.

Aqui não existe prompt onde apontar um caminho sobrevivente, então a correção é automática: --add-dir para o checkout claude/ mais CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD. O segundo --add-dir traz o claude/shellhub/CLAUDE.md, que nunca chegou à sessão.

Testes

actionlint e yamllint limpos. Como sempre neste repo, este PR não exercita a própria mudançapull_request_target e issue_comment rodam o workflow do branch base. Quem verifica é o shellhub-io/cloud#2554, que dispara em pull_request.

Ordem de merge: claude#65, depois cloud#2554 (conferir o run), depois este.

This workflow syncs the config and then runs an action that deletes it: .claude/ and CLAUDE.md at
the workspace root are replaced with the base branch's copies, and this repo tracks neither, so
they are replaced with nothing. Every @claude invocation has been running without the repo rules,
without the skills and without CLAUDE.md.

Unlike the review workflow there is no prompt here to point at a surviving path, so the fix has to
be one the runtime applies on its own. --add-dir for the claude checkout does it: skills become
invocable by name, and CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD loads CLAUDE.md and every
.claude/rules/*.md from the added directories. The second --add-dir carries this repo's own
CLAUDE.md, which lives at claude/shellhub/ and never reached the session at all.

Verified on cloud by planting a distinct token in each location with every file-reading tool
denied, so a token could only appear if the runtime supplied it.
@otavio
otavio requested a review from a team as a code owner September 12, 2026 20:44
@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown

Claude finished @otavio's task in 12m 20s —— View job


Code Review Complete

Reviewed 1 file. 1 inline issue posted — Standards: 0 violations, 1 judgement call. Spec: axis did not run. Correctness: 0.

Standards

--add-dir ${{ github.workspace }}/claude (line 118) reintroduces claude/CLAUDE.md, which workspace.sh sync --project shellhub deliberately replaces with the project file in CI — and its Projects table asserts ShellHub lives at shellhub/, which is false in this job where the workspace root is the shellhub checkout.

Spec

The Spec axis did not run: the PR references no issue, only the paired PRs shellhub-io/claude#65 and shellhub-io/cloud#2554. A spec is never reconstructed from the PR title.

Additional notes

The mechanism checks out end to end, against the action source at the pinned SHA rather than from memory: --add-dir accumulates into additionalDirectories (base-action/src/parse-sdk-options.ts:210-216), the step's env reaches the CLI as {...process.env} (:279), CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD is a recognised CLI env var, and the nested second --add-dir is accepted — the "denied with an error" wording in the SDK typings governs the runtime register_repo_root request, not launch-time additionalDirectories. This session is itself a run of the mechanism: the workspace root has no CLAUDE.md and no .claude/settings.json, only the .claude-pr/ snapshot, so every rule and skill in context arrived through these two flags. The bug is real and the fix works.

No correctness findings. --add-dir widens nothing: both roots are already strict subdirectories of the action's cwd, so they were readable and writable before this diff; settingSources stays ["user","project","local"] and resolves project against cwd, so no settings.json or hook is activated from an added root; and the checkout at lines 96-102 runs before the agent, so a fork cannot plant a claude/ for it to pick up.

One judgement call was dropped below the reporting bar: on plain-issue @claude comments restoreConfigFromBase is skipped (run.ts:263 gates on context.isPR) while workspace.sh sync still runs, so the config loads twice. Real, but token cost only, and the remedy relocates the duplication rather than removing it.


To request another review round, comment /review.
· ci/pr-review-config-via-add-dir

Without it the job cannot tell a review that finished quietly from one that failed, and it was
rewriting both to "no new issues were found". On cloud#2554 that turned a review which exhausted
its turn cap into a clean bill of health.
github_token: ${{ secrets.GITHUB_TOKEN }}
trigger_phrase: "@claude"
claude_args: |
--add-dir ${{ github.workspace }}/claude

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Standards (judgement call) — writing-for-agents: "Check every line for relevance: does it still bear on what the document does? A line loses relevance by never bearing on the task … or by going stale as the behaviour or world it describes changes."

This line plus CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 loads claude/CLAUDE.md — the workspace-root memory that the step right above deliberately does not install here. workspace.sh:145-151 picks the project file instead when --project is set:

# In CI, we link the project-specific CLAUDE.md (e.g., claude/shellhub/CLAUDE.md)
# instead of the root one, since the workspace root IS the project checkout.
local claude_md="$SCRIPT_DIR/CLAUDE.md"
if [[ -n "${sync_project:-}" ]]; then
    claude_md="$SCRIPT_DIR/$sync_project/CLAUDE.md"
fi

The env var reaches every added dir, so --add-dir .../claude brings that file back through a side channel. Its Projects table is the part that has gone stale for this job's layout — the checkout at line 62 has no path:, so the workspace root is the shellhub checkout, while cloud/ and claude/ are nested under it:

Row In this job
ShellHub → shellhub/ wrong — no such directory
Cloud → cloud/, Claude → claude/ correct
Connect → connect/, Docs → docs/, Team → team/ not checked out

So the session gets the lead row asserting a path that does not exist, sitting next to claude/shellhub/CLAUDE.md, which correctly assumes root-as-checkout. Concrete cost: an @claude run that takes the table at face value goes looking under shellhub/ for files that are at the root.

Worth noting the obvious fix is not dropping this line. On PR runs restoreConfigFromBase wipes the root .claude/ before the session starts, so --add-dir .../claude is exactly what delivers the rules and skills — remove it and you reopen the bug. The stale table is a claude/CLAUDE.md problem, so the fix belongs in shellhub-io/claude#65: scope that table, or note that in CI the workspace root is the project checkout.

claude-code-review.yml sets persist-credentials: false on the identical checkout; this one did not,
so the app token stayed in claude/.git/config for the life of the job. Nothing here pushes from that
checkout — it supplies config the CLI reads.
workspace.sh sync cannot report this class of failure: every step in sync_root is a conditional
skip, not a check, so the script exits 0 having linked nothing. That is how every @claude
invocation ran without the repo rules, the skills and CLAUDE.md with a human present each time and
nobody noticing — the symptom is "Claude seems worse lately", never a red check.

--add-dir removes today's cause. This removes the silence, so the next regression in the same seam
— a workspace.sh layout change, a renamed claude/shellhub/, a wrong path: — stops the job instead
of quietly degrading the model. The review workflow already guards its own config this way.

Raised by the review on cloud#2554.
@otavio
otavio merged commit f7ec2a3 into master Sep 12, 2026
41 checks passed
@otavio
otavio deleted the ci/pr-review-config-via-add-dir branch September 12, 2026 21:46
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