Context
A run of /claude-ops:audit-install-state on 2026-09-08 inside a Claude Code on the web container returned a confident "healthy, nothing stale" verdict on /root/.claude, a tree that was three minutes old and not the operator's workstation. The report carries no signal that the tree belongs to an ephemeral container, so a reader who invoked the skill from the web UI gets an answer about the wrong machine and has to notice the mtimes themselves.
Upstream documents one signal for this: CLAUDE_CODE_REMOTE is "Set automatically to true when Claude Code is running as a cloud session" (env-vars.md, fetched 2026-09-11). That variable describes the running process, not the scanned tree, and the engine accepts --root <path>, so it cannot be the tree verdict on its own. Tree-level signals observed in the container and absent from every official page fetched that day (claude-directory.md, plugins-reference.md, env-vars.md, hooks.md, cloud-environments.md, plugin-marketplaces.md, CHANGELOG through 2.1.268): launcher-settings.json, environment-manager/, and four hook scripts at the tree root. plugins/synced/ is documented (plugins-reference.md) and is also cloud-specific. session-env/, remote-settings.json, and policy-limits.json are NOT discriminating: the first is documented as per-session metadata on every install, the other two are server-managed settings caches that a local install can carry too.
The engine's evidence vocabulary is a closed set today (install_state.py header and reference/evidence-discipline.md section 1), so the new block needs an explicit vocabulary extension and a schema version bump rather than a silent parallel tag.
The cost of leaving it: every cloud-session run of a skill whose stated purpose is "is this tree in a deliberate or experimental state?" misreads the most common experimental state there is.
Proposed work
- Add an
environment block to the JSON report with two parts: a session-context line (CLAUDE_CODE_REMOTE value, tagged as a property of the auditing process, plus a root_is_own_config_dir boolean derived from --root versus the resolved config dir) and a tree-signal list (launcher-settings.json, environment-manager/, root-level *.sh / *.py hook scripts, plugins/synced/), each row carrying its own evidence tag.
- Extend the evidence vocabulary explicitly (for example
documented and observed-undocumented) in install_state.py and reference/evidence-discipline.md, and bump schema from claude-install-state/1 to /2; add tests for the new block, including the false-positive guard that a local tree with only session-env/ never reads as remote.
- Add the tree-level verdict
remote | local | indeterminate and require at least one tree signal for remote; a process-level CLAUDE_CODE_REMOTE=true with no tree signal, or conflicting signals, yields indeterminate.
- SKILL.md: add the environment read as the first thing the reader checks, and reword the current "Before reading any other part of the report, read
deliberate_state and deny_roots" sentence so the two instructions do not contradict each other; add one line pointing remote sessions at the session scratchpad for the --csv and JSON destinations.
- While editing SKILL.md, move phase detail that the
reference/ files already own out of the hub so the file drops under the skill-quality soft cap of 200 lines (it is 237 today and /skill-quality:check emits a WARN); the trim is part of this issue, not a separate one.
- Record the undocumented signals with a four-part record (claim, basis, as-of date and CLI version, recheck trigger) per
.claude/rules/skill-bodies-state-current-rules.md. Do not add CLAUDE_CODE_REMOTE_ENVIRONMENT_TYPE or other CLAUDE_CODE_REMOTE_* / CCR_* variables as signals until a page documents them.
Acceptance criteria
References
- Run evidence: 2026-09-08 report, tree age 3 minutes,
quiesced: false, no deliberate_state, 13,734 files.
- env-vars.md
CLAUDE_CODE_REMOTE row; plugins-reference.md plugins/synced/; claude-directory.md session-env/ row (all raw markdown, fetched 2026-09-11).
plugins/claude-ops/skills/audit-install-state/scripts/install_state.py: --root handling, evidence constants, SURFACE_TABLE entry for session-env.
reference/evidence-discipline.md section 1 (evidence vocabulary), .claude/rules/skill-bodies-state-current-rules.md.
- Related: the sibling issue on the largest-subtree attribution (same run), filed alongside this one.
Metadata
| Field |
Value |
| Category |
unspecified |
| Area |
unspecified |
| Ecosystem |
unspecified |
Generated by Claude Code
Context
A run of
/claude-ops:audit-install-stateon 2026-09-08 inside a Claude Code on the web container returned a confident "healthy, nothing stale" verdict on/root/.claude, a tree that was three minutes old and not the operator's workstation. The report carries no signal that the tree belongs to an ephemeral container, so a reader who invoked the skill from the web UI gets an answer about the wrong machine and has to notice the mtimes themselves.Upstream documents one signal for this:
CLAUDE_CODE_REMOTEis "Set automatically totruewhen Claude Code is running as a cloud session" (env-vars.md, fetched 2026-09-11). That variable describes the running process, not the scanned tree, and the engine accepts--root <path>, so it cannot be the tree verdict on its own. Tree-level signals observed in the container and absent from every official page fetched that day (claude-directory.md, plugins-reference.md, env-vars.md, hooks.md, cloud-environments.md, plugin-marketplaces.md, CHANGELOG through 2.1.268):launcher-settings.json,environment-manager/, and four hook scripts at the tree root.plugins/synced/is documented (plugins-reference.md) and is also cloud-specific.session-env/,remote-settings.json, andpolicy-limits.jsonare NOT discriminating: the first is documented as per-session metadata on every install, the other two are server-managed settings caches that a local install can carry too.The engine's evidence vocabulary is a closed set today (
install_state.pyheader andreference/evidence-discipline.mdsection 1), so the new block needs an explicit vocabulary extension and a schema version bump rather than a silent parallel tag.The cost of leaving it: every cloud-session run of a skill whose stated purpose is "is this tree in a deliberate or experimental state?" misreads the most common experimental state there is.
Proposed work
environmentblock to the JSON report with two parts: a session-context line (CLAUDE_CODE_REMOTEvalue, tagged as a property of the auditing process, plus aroot_is_own_config_dirboolean derived from--rootversus the resolved config dir) and a tree-signal list (launcher-settings.json,environment-manager/, root-level*.sh/*.pyhook scripts,plugins/synced/), each row carrying its own evidence tag.documentedandobserved-undocumented) ininstall_state.pyandreference/evidence-discipline.md, and bumpschemafromclaude-install-state/1to/2; add tests for the new block, including the false-positive guard that a local tree with onlysession-env/never reads as remote.remote | local | indeterminateand require at least one tree signal forremote; a process-levelCLAUDE_CODE_REMOTE=truewith no tree signal, or conflicting signals, yieldsindeterminate.deliberate_stateanddeny_roots" sentence so the two instructions do not contradict each other; add one line pointing remote sessions at the session scratchpad for the--csvand JSON destinations.reference/files already own out of the hub so the file drops under the skill-quality soft cap of 200 lines (it is 237 today and/skill-quality:checkemits a WARN); the trim is part of this issue, not a separate one..claude/rules/skill-bodies-state-current-rules.md. Do not addCLAUDE_CODE_REMOTE_ENVIRONMENT_TYPEor otherCLAUDE_CODE_REMOTE_*/CCR_*variables as signals until a page documents them.Acceptance criteria
CLAUDE_CODE_REMOTE=trueandlauncher-settings.jsonpresent) emitsenvironment.tree_verdict: remotewith every signal row tagged, and the chat report's first line names the tree as the container's.session-env/,remote-settings.json, andpolicy-limits.jsonbut none of the tree signals emitstree_verdict: local.CLAUDE_CODE_REMOTE=truebut no tree signal is present, or signals conflict, THENtree_verdictisindeterminate, neverremote.schemareadsclaude-install-state/2; the evidence vocabulary extension is documented inreference/evidence-discipline.md; the test suite covers the three verdicts./skill-quality:check audit-install-statereports no line-count WARN (SKILL.md under 200 lines) with no rule lost, only relocated toreference/.References
quiesced: false, nodeliberate_state, 13,734 files.CLAUDE_CODE_REMOTErow; plugins-reference.mdplugins/synced/; claude-directory.mdsession-env/row (all raw markdown, fetched 2026-09-11).plugins/claude-ops/skills/audit-install-state/scripts/install_state.py:--roothandling, evidence constants,SURFACE_TABLEentry forsession-env.reference/evidence-discipline.mdsection 1 (evidence vocabulary),.claude/rules/skill-bodies-state-current-rules.md.Metadata
Generated by Claude Code