Skip to content

New-PC Claude Code user profile: native claude-code pin, guard, agents, user-scope MCP, settings apply - #139

Merged
seathatflowsinourveins merged 5 commits into
mainfrom
claude/claude-user-profile-20260923
Sep 23, 2026
Merged

seathatflowsinourveins merged 5 commits into
mainfrom
claude/claude-user-profile-20260923

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Collaborator

What

Reproduces this host's current best-practice Claude Code profile on a new Linux/WSL or macOS PC from the catalog:

  • Pins: native claude-code 2.1.280 on both platforms (the binary's sha256 matches the release manifest; it auto-updates on the latest channel; the launcher is named by the pin's bin). The winners markitdown and tavily-cli install as uv tools; orx from a tarball; agent-browser from npm (Linux).
  • Profile assets: adoption/hooks/claude/effort-default-guard.py (sha256-checked), five lean agents in adoption/agents/claude/, and user-scope MCP templates in adoption/mcp/claude-user.json (ai-memory, jCodeMunch, Serena).
  • Tools:
    • tools/adoption/install_claude_profile.py (guard, agents, MCP): renders ${HOME} and ${ECO_ROOT}, runs mcp add --scope user <name> -e … -- <cmd>, and leaves a differing server unchanged unless --replace-mcp.
    • tools/adoption/apply_claude_settings.py: deep merge; hook de-duplication across each event by shell words; backups never overwrite an earlier one.
    • Bootstrap flag --configure-claude-user-profile.
  • Template: regenerated from the live host: opus[1m], modelSettings.claude-opus-5-5.effortLevel=xhigh, ultracode, showThinkingSummaries, cleanupPeriodDays 3650, autoContinueAtUsageLimit, and the guard hooks.
  • Docs: decision record docs/decisions/2026-09-23-claude-user-profile.md, plus dated community-disposition rows. New-host pages mark every install input changed or added after v2026.09.23.

Evidence

  • An independent Opus review of the builder commit found 4 blocking and 8 secondary defects. All are fixed in e6ca4dd6/74972f81:
    • launcher name
    • unrendered MCP placeholders and the -e argument order
    • hook duplication across groups and matchers
    • nested-dict replacement
    • backup overwrite
    • pip entry points
    • stale base
    • the uninvented system-package kind
    • doc citations and a wrong hash tail
  • MCP step, real CLI. claude 2.1.280 in a temporary CLAUDE_CONFIG_DIR registered all three servers with rendered paths; a second run skipped all three. The host's ~/.claude.json MCP entries were unchanged.
  • Settings apply. Applying the rendered template to this host's live settings is a no-op (idempotent), and host-only permissions, plugins and per-model levels are kept.
  • Checks:
    • Guard, apply and install suites: 47 tests pass.
    • Bootstrap, docs-consistency and profile suites: 218 tests OK (3 skipped).
    • Validators pass: validate.py (2,470 hashed files), validate_catalogs.py, evidence_manifest.py --check, new_host_grand_list.py --check.
    • Guarded gitleaks: 3 commits, no leaks.
  • Full suite locally. Main and this branch fail on exactly the same IDs: 10 failures and 31 errors (the adaptive-paper stop_blocks_entry errors among them). This branch adds no new failures.

Not verified

  • No end-to-end bootstrap run on a clean PC or a sandboxed HOME.
  • The macOS native case is covered by plan and text tests only.
  • The 2.1.280 manifest .sig is unverified.
  • Poppler is unpinned (not installed on this host).

🤖 Generated with Claude Code

…d/agents/MCP assets, apply tooling

Pin claude-code to the native 2.1.280 self-installing binary on both
Linux and macOS (dropping the npm wrapper + platform_dependency design
for macOS), ship this host's verified effort-default-guard.py hook, the
five project agents, and the ai-memory/jcodemunch/serena user-scope MCP
template as reusable adoption assets. Add
tools/adoption/apply_claude_settings.py (deep-merging settings template
apply) and tools/adoption/install_claude_profile.py (idempotent
guard/agents/MCP install), wired into both bootstrap scripts via
--configure-claude-user-profile. Update the settings template to match
the live host (Opus 5.5 modelSettings, ultracode, workflow env, guard
hooks) and record four already-installed catalog winners (markitdown,
tavily-cli, orx, agent-browser) in the Linux pins, each independently
re-verified against its publisher. Add a dated 2026-09-23 community
disposition review and a decision record for this round's evidence and
overturn conditions.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…, event-wide hook dedup

- install_native names the launcher after the pin's `bin` (claude-code -> claude),
  so the --configure-claude-user-profile step finds $bin_dir/claude.
- markitdown and tavily-cli install as uv tools (own venv), matching this host's receipts;
  VALID_KINDS no longer lists an uninvented kind.
- install_claude_profile renders ${HOME}/${ECO_ROOT} (--eco-root), orders
  `mcp add --scope user <name> -e K=V -- <command> ...`, and leaves a differing
  same-named server unchanged unless --replace-mcp. Verified against claude 2.1.280
  under a temporary CLAUDE_CONFIG_DIR: registers all three, second run skips all three.
- apply_claude_settings de-duplicates hooks across the whole event by shell words,
  keeps absent and "" matchers distinct, deep-merges every nested object with list
  union, and never overwrites an earlier backup. Applying the rendered template to
  this host's settings is a no-op.
- Guard tests skip when a managed-settings file exists and cover heal-once and an
  explicit lower session effort; doc rows cite in-repo sources; darwin hash tail fixed.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…h after the rebase

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-23T19:05:58.041905Z 74972f8 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

…; exact MCP matching

- install_native skips its launcher when bin_dir is ~/.local/bin (the native
  installer's own symlink into ~/.local/share/claude/versions) and removes an
  existing launcher path before writing, so the redirect never writes through a
  symlink. Behavioral test runs each script's install_native with a stub
  installer; the previous code overwrote the versioned binary in that case.
- The printed follow-up command carries --eco-root; default_eco_root follows --home.
- MCP matching parses `claude mcp get` fields (Type, Command, Args in order,
  URL, Environment names) from recorded 2.1.280 output, and `mcp get` runs from
  an empty temporary directory so project/local entries cannot shadow the user one.
  Real CLI under a temporary CLAUDE_CONFIG_DIR: register, skip, differs (left
  unchanged), --replace-mcp dry run shows the remove, re-register.
- Backups skip dangling-symlink names; malformed hook groups no longer crash apply.
- evidence.json keeps the canonical writer's ASCII escapes.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…ne, clean missing-claude failure

The printed follow-up command also names --claude-bin. Tests cover a Headers
line named URL, a managed-scope server (no remove/add) and a missing binary.
Real CLI re-check under the temporary CLAUDE_CONFIG_DIR: all three skipped.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@seathatflowsinourveins
seathatflowsinourveins enabled auto-merge (squash) September 23, 2026 18:56
@seathatflowsinourveins
seathatflowsinourveins merged commit cd5db09 into main Sep 23, 2026
21 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/claude-user-profile-20260923 branch September 23, 2026 18:59

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

https://github.com/seathatflowsinourveins/native-agent-stack/blob/74972f8145d89e94090207df91ac1f755df44797/adoption/bootstrap-linux.sh#L330-L334
P2 Badge Verify uv-tool downloads against the committed hashes

When a uv-tool pin such as the newly added markitdown or tavily-cli is selected, this path ignores both the pinned artifact URL and its SHA-256 and asks uv to resolve the package from the index. A changed or differently resolved artifact can therefore be installed successfully despite the bootstrap's stated fail-closed SHA-256 guarantee; install from the fetched, verified artifact or otherwise bind uv to the committed digest.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +8 to +10
"jcodemunch": {
"type": "stdio",
"command": "${ECO_ROOT}/bin/jcodemunch-mcp",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Install MCP executables before registering them

On a fresh foundation-cpu bootstrap using --configure-claude-user-profile, this registers jcodemunch-mcp and serena-context paths that do not exist: neither executable has an entry in either platform pin file, and no profile in adoption/manifest.json installs either component. The registration itself can therefore succeed while two advertised MCP servers fail whenever Claude launches them; install these prerequisites or omit their registrations until their native recipes have run.

AGENTS.md reference: AGENTS.md:L47-L50

Useful? React with 👍 / 👎.

Comment on lines +231 to +233
if "mcp" in steps:
eco_root = Path(args.eco_root) if args.eco_root else default_eco_root()
install_mcp_servers(args.claude_bin, args.dry_run, home, eco_root, args.replace_mcp)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Honor the target home during MCP setup

When --home differs from the caller's actual home, the guard and agents are copied under the requested target, but the MCP subprocesses still inherit the caller's environment and default_eco_root() also derives its default from Path.home(). Thus the same invocation mutates the caller's Claude configuration and renders commands against the caller's ecosystem prefix instead of the advertised target home; derive the default prefix from home and run Claude with the target configuration environment.

AGENTS.md reference: AGENTS.md:L61-L61

Useful? React with 👍 / 👎.

WANT = "xhigh"
RANK = {"low": 0, "medium": 1, "high": 2, "xhigh": 3, "max": 4}
USER = os.path.expanduser("~/.claude/settings.json")
MANAGED = "/etc/claude-code/managed-settings.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Read managed settings from the macOS location

On the newly supported macOS profile, the guard only checks Linux's /etc/claude-code/managed-settings.json and therefore misses macOS managed policy. A managed per-model effort or maxEffortLevel can be ignored, causing incorrect SessionStart advice and a misleading user-level self-heal after SessionEnd; select Claude Code's platform-specific managed-settings path before resolving or saving effort.

AGENTS.md reference: AGENTS.md:L61-L61

Useful? React with 👍 / 👎.

Comment on lines +230 to +233
parser.add_argument("--template", default=str(DEFAULT_TEMPLATE),
help="Rendered claude.settings.template.json to merge in "
"(render it first with tools/adoption/render_config.py --out; "
"this tool does not substitute ${...} placeholders itself)")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject the unrendered default settings template

Invoking this tool without --template silently selects the repository's raw template even though the adjacent help text says it must be rendered first. The merge then writes literal ${ECO_ROOT}, ${HOME}, and ${HOST_PATH} values and keeps escaped template syntax such as $$schema, leaving PATH and hook commands unusable in the live Claude configuration; require an explicitly rendered file or reject unresolved placeholders before writing.

AGENTS.md reference: AGENTS.md:L61-L61

Useful? React with 👍 / 👎.

Comment on lines +76 to +78
dest_dir.mkdir(parents=True, exist_ok=True)
shutil.copy2(GUARD_SRC, dest)
dest.chmod(0o755)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Refuse symlinked profile destinations

If an existing guard destination is a symlink whose target differs from the catalog copy, shutil.copy2 follows the link and overwrites that external target, after which chmod also changes its mode to 0755; the agent-copy loop has the same behavior. This can corrupt a user- or configuration-manager-owned file outside ~/.claude/hooks or ~/.claude/agents, so reject symlink destinations or atomically replace the link itself rather than following it.

AGENTS.md reference: AGENTS.md:L61-L61

Useful? React with 👍 / 👎.

os.chmod(tmp, os.stat(USER).st_mode & 0o777)
except OSError:
pass
os.replace(tmp, USER)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize SessionEnd settings updates

When two Claude sessions end concurrently, or a user edits settings while this hook runs, each process can load the same old JSON and then replace the entire settings file with its own stale copy. Atomic replacement prevents a partial file but not this lost-update race, so one model's self-heal can erase another model entry or unrelated settings changes made after line 117; lock the read-modify-write cycle or revalidate and merge immediately before replacement.

AGENTS.md reference: AGENTS.md:L6-L8

Useful? React with 👍 / 👎.

Comment on lines +120 to +124
if command_or_url not in existing_text:
return False
for arg in args:
if arg and arg not in existing_text:
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Compare structured MCP configurations

For an existing stdio registration, matching each desired command and argument as an arbitrary substring accepts materially different configurations—for example, command /e/bin/jcodemunch-mcp-evil matches /e/bin/jcodemunch-mcp, and extra or reordered arguments are never rejected. Such an entry is reported as matching and skipped, leaving the intended user-scope server undiscovered; parse the returned fields and compare the exact command and argument vector.

AGENTS.md reference: AGENTS.md:L61-L61

Useful? React with 👍 / 👎.

Comment on lines +306 to +311
{
printf '#!/usr/bin/env bash\n'
printf '# Native auto-updating launcher (installed by %s install); the ecosystem no longer pins a snapshot.\n' "$id"
# shellcheck disable=SC2016
printf 'exec "$HOME/.local/bin/%s" "$@"\n' "$bin_name"
} > "$bin_dir/$bin_name"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid overwriting the native launcher with a recursive wrapper

If a caller chooses the otherwise accepted ECO_INSTALL_ROOT=$HOME/.local, then bin_dir/claude is the same path as the native installer's $HOME/.local/bin/claude. This write replaces the real launcher with a wrapper that execs itself forever; the later version-report loop masks the resulting nonzero --version, so the bootstrap can still print completion with Claude unusable. Both platform scripts share this implementation, so reject overlapping roots or avoid creating a wrapper when both paths resolve to the same file.

AGENTS.md reference: AGENTS.md:L61-L61

Useful? React with 👍 / 👎.

Comment on lines +5 to +7
model: sonnet
effort: medium
isolation: worktree

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound every installed worker's turns

The installed isolated-builder, evidence-reviewer, and semantic-evidence-reviewer omit maxTurns, unlike the bounded source-scout and blind-judge. When one of these roles enters an unproductive tool or review loop, the profile's concurrency and spawn-depth limits do not cap that worker's sequential turns, leaving execution and usage unbounded; add task-appropriate turn ceilings to each shipped role.

AGENTS.md reference: AGENTS.md:L6-L8

Useful? React with 👍 / 👎.

seathatflowsinourveins added a commit that referenced this pull request Sep 25, 2026
…tions to their host; record sparse-VHD, gitleaks-order and WSL lessons (#230)

* Run Serena's own script from the MCP templates; attribute pin observations to their host; record sparse-VHD, gitleaks-order and WSL lessons

- adoption/mcp/claude-user.json and adoption/templates/project.codex.config.template.toml
  launched serena through ${ECO_ROOT}/bin/serena-context, a wrapper that existed
  only on the 2026-09-23 recording host (it set SERENA_HOME); nothing in this
  repository creates it. Both now run ${ECO_ROOT}/bin/serena with the same
  arguments: the console script `uv tool install` links there for serena-agent
  at the stack pin c6fbd1c5 with the bootstrap's uv-tool layout. The template
  comment gives that command and says the ai-memory URL (127.0.0.1:49374, the
  repository default) must match the host's own ai-memory unit.
- tests/test_install_claude_profile.py follows the template, keeps the
  2026-09-23 `claude mcp get` recording, adds a 2026-09-25 recording of the
  new registration (claude 2.1.282, temporary CLAUDE_CONFIG_DIR) and checks
  that the older registration is reported as differing.
- adoption/pins-linux-x86_64.json: the markitdown, tavily-cli, orx and
  agent-browser install notes attribute their "installed" observation to the
  host that recorded PR #139 on 2026-09-23. Versions, URLs and hashes are
  unchanged.
- docs/next-host-stages.md and docs/new-workstation-runtime-profile-20260922.md:
  dated notes that sparseVhd is disabled upstream (enabling it needs
  --set-sparse true --allow-unsafe), how to reclaim VHD space instead, and the
  workstation's live .wslconfig, which differs from the projection.
- docs/secret-storage.md step 5: install and verify gitleaks 8.30.1 and the
  guarded launcher (5a) before enabling the hook (5b).
- adoption/platforms/linux-wsl2.md: Windows-side command and listener lessons,
  each with its upstream source.
- docs/acceptance-evidence-policy.md: discriminating controls.
- manifests/evidence.json: re-registers the eight hash-listed files.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Disclose the install_note-only pins change on the two pages that cite the pin file

tests.test_adoption_docs_consistency requires every page that mentions
adoption/pins-linux-x86_64.json to say what changed after the pinned
release. adoption/bootstrap.md and adoption/platforms/macos-arm64.md now say
the change is install_note text only; versions, URLs and hashes are
unchanged. manifests/evidence.json re-registers both files.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Install the MCP servers the template names; safe re-registration; hook check with a planted-key control

Independent-review repair round for #230.

- adoption/bootstrap.md step 4a installs serena (git pin c6fbd1c5) and
  jcodemunch-mcp 1.108.319 as uv tools into ${ECO_ROOT}/python-tools and
  ${ECO_ROOT}/bin before the MCP registration. It names the MCP template and
  the project Codex template among the files changed after v2026.09.24.1 (the
  tag's serena entry runs a serena-context wrapper nothing installs), and gives
  the re-registration sequence: remove the servers that should change, then
  install_claude_profile.py --only mcp without --replace-mcp. That flag
  re-registers every differing server. An ai-memory unit on another port needs
  `claude mcp remove ai-memory -s user` before `claude mcp add`, because
  `claude mcp add` refuses an existing name.
- adoption/mcp/claude-user.json comment and adoption/platforms/linux-wsl2.md
  say the same; the port rule applies to the registration, not the template.
  adoption/platforms/macos-arm64.md step 3 names the template change.
- recipes/README.md serena row points at the installed command and
  bootstrap step 4a, and keeps uvx for one-off runs.
- docs/secret-storage.md: 5a names $ECO_INSTALL_ROOT/tools/gitleaks-8.30.1/
  as the extraction target with checksum-verified commands, and says how
  `gitleaks` resolves to gitleaks-guarded-macos on macOS and what passes. 5b
  checks core.hooksPath and runs `git hook run pre-commit` in a throwaway
  worktree, clean (exit 0) and with a planted generated AWS-style key
  (exit 1). The hook is absent at v2026.09.24.1.
- adoption/tools/README.md macOS install adds the `gitleaks` link and its
  pass criterion.
- docs/acceptance-evidence-policy.md: the failing control is recorded with the
  passing run, the rule governs new claims, and the planted-key check is the
  example.
- docs/next-host-stages.md: Optimize-VHD -Mode Full needs Mount-VHD -ReadOnly.
  docs/new-workstation-runtime-profile-20260922.md compares each live value
  with its projection.
- manifests/evidence.json re-registers the nine hash-listed files.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

---------

Co-authored-by: Scout <scout@local>
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
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