fix(onboarding): /home install flow + agnes init UX hardening (#350)

* fix(web): /home Step 2 recommends --dangerously-skip-permissions for setup

The Step 4 paste runs ~20 shell commands (CLI install, workspace
bootstrap, marketplace clone, MCP register, connector logins). Previous
Step 2 recommended auto-accept-edits via Shift + Tab, which covers file
edits but not Bash — users still clicked ~20 Yes prompts during setup.

Step 2 now leads with `claude --dangerously-skip-permissions` as the
recommended session flag (Bash + edits both skip). Session-scoped, drops
on next plain `claude` — safe here because the pasted script is
generated by this server and ends after a fixed sequence; the flag does
not weaken future Claude sessions.

Auto-accept-edits via Shift + Tab kept as the strict-review fallback;
persistent YOLO allowlist link to /setup-advanced#yolo unchanged.

* fix(web): swap /home Steps 2↔3, claude --yolo as copy-button command

Folder creation moves to Step 2; Step 3 launches Claude from that
directory with `claude --dangerously-skip-permissions`. The YOLO flag
is rendered through the standard .install-cmd + copy-button affordance
(matching Step 1 + Step 2), not inline prose. Step 4 paste runs ~20
shell commands that auto-accept-edits would not cover (Bash still
prompts), so the YOLO flag is the default recommendation; session-
scoped, drops on next plain `claude`.

Setup script's pwd-check warning copy refreshed to reference "/home
Step 2" (the new folder-creation step number).

# Conflicts:
#	CHANGELOG.md

* fix(web): open YOLO setup-advanced link in new tab

Step 3 install-hero's persistent-YOLO link now opens /setup-advanced#yolo
in a new window so users don't lose their /home install context mid-
setup. target="_blank" + rel="noopener" (no reverse-tabnabbing).

* fix(web): merge /home Step 3 fallback prose into prior paragraph

Drop the <br><br> between the 'Session-scoped' line and the 'Prefer
reviewing each command' line so the strict-review fallback flows on
the same paragraph — less vertical space in the install-hero block.

* docs(web): add "What leaves your machine" privacy callout on /home

Install-hero lead now includes a short privacy paragraph: explains that
session telemetry (prompts / tool-calls / tool-responses) flows back to
the central catalog for failure-pattern analysis while raw data rows
the user queries locally stay on their machine. Points at /agnes-private
as the per-session opt-out.

Also collapses leftover cherry-pick conflict markers in CHANGELOG.md
into one clean [Unreleased] section.

* fix(init): harden agnes init UX — 5 issues from David's report

1. chmod +x hooks. agnes init + agnes refresh-marketplace --bootstrap
   now set the execute bit on every .sh they land on disk
   (`<workspace>/.claude/hooks/*.sh` after init; every `.sh` under the
   `~/.agnes/marketplace` clone after a bootstrap/pull). Git checkout
   doesn't always preserve filemode (filemode=false repos, ZIP
   extractions), so hooks were firing with "Permission denied" — silent
   SessionStart / PreToolUse breakage. Best-effort, no-op on Windows.

2. --token-file + AGNES_TOKEN. agnes init now accepts `--token-file
   <path>` and an `AGNES_TOKEN` env fallback alongside `--token`.
   Precedence: --token > --token-file > AGNES_TOKEN. The file / env-var
   paths dodge Claude Code's auto-classifier, which sometimes flags a
   long bearer token in `--token "eyJ..."` command line as a credential-
   exfil pattern. The pasted setup script now uses `--token-file
   ~/.agnes/token` (token written via single-quoted heredoc, umask 077)
   for the same reason.

3. Bash(agnes *) in allow. Default `.claude/settings.json` permissions.
   allow seeded by agnes init now includes `Bash(agnes *)` alongside the
   bare `Bash` entry, so Claude Code's classifier sees an explicit allow
   for subsequent `agnes <verb>` calls inside the workspace it just
   bootstrapped.

4. .zshrc PATH dedup. Setup-script step 1's PATH-persist snippet
   (no-CA install path) replaced with a `grep -qF + ||` idiom so a
   re-run doesn't append a duplicate `export PATH=...` line. Fixed-
   string match (not regex) per the dedup-bug report.

5. `!` prefix doc note. Setup-script step 3 now explicitly tells the
   user: if Claude Code blocks an `agnes` command, prefix it with `!`
   (e.g. `! agnes init …`) to run the command directly in the shell,
   bypassing the auto-classifier.

* release: 0.55.1 — /home onboarding install-hero rework + agnes init UX hardening

---------

Co-authored-by: ZdenekSrotyr <zdenek.srotyr@keboola.com>
This commit is contained in:
Vojtech 2026-05-19 17:26:35 +04:00 committed by GitHub
parent 64cf78860d
commit ae67c40a81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 239 additions and 38 deletions

View file

@ -10,6 +10,58 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
## [Unreleased]
## [0.55.1] — 2026-05-19
### Added
- `/home` install-hero lead now includes a short "What leaves your
machine" privacy callout: explains that prompts / tool-calls /
tool-responses travel back to the central catalog while raw data
rows stay local, and points at `/agnes-private` as the per-session
opt-out.
- `agnes init` now accepts `--token-file <path>` and `AGNES_TOKEN`
env-var fallback alongside `--token`. Precedence: `--token` >
`--token-file` > `AGNES_TOKEN`. The file-/env-var paths dodge
Claude Code's auto-classifier, which sometimes flags a long bearer
token in an `--token "eyJ..."` command line as a credential-exfil
pattern. The pasted setup script now uses `--token-file
~/.agnes/token` (token written via single-quoted heredoc, umask 077)
for the same reason.
### Changed
- `/home` onboarding install-hero reordered: folder creation is now
Step 2 (was Step 3) and starting Claude with
`claude --dangerously-skip-permissions` is the new Step 3, rendered
with the same `.install-cmd` + copy-button affordance as the other
steps. Step 4 paste runs ~20 shell commands that auto-accept-edits
would not cover (Bash still prompts), so the YOLO flag is the
default recommendation (session-scoped, drops on next plain
`claude`). Shift + Tab → auto-accept-edits kept as the strict-
review fallback; persistent YOLO allowlist link to
`/setup-advanced#yolo` opens in a new tab so users don't lose
their `/home` install context. Setup script's "Verify cwd" warning
copy refreshed to reference "/home Step 2".
- `agnes init` adds `Bash(agnes *)` to the default `permissions.allow`
list in the seeded `.claude/settings.json`. Without it, Claude Code
was blocking subsequent `agnes <verb>` invocations (`agnes catalog`,
`agnes pull`, …) inside the workspace it had just bootstrapped.
- `agnes init` and `agnes refresh-marketplace --bootstrap` now
`chmod +x` every `.sh` they land on disk
(`<workspace>/.claude/hooks/*.sh` after init; every `.sh` under
`~/.agnes/marketplace` after a clone/pull). Git checkout doesn't
always preserve the file-mode bit (filemode=false repos, ZIP
extractions), so hooks were firing with "Permission denied" —
silent `SessionStart` / `PreToolUse` breakage. Best-effort: no-op
on Windows NTFS.
- Setup script step 3 now uses `--token-file ~/.agnes/token` plus a
single-quoted heredoc for the token write, and includes an explicit
note about the `!` prefix fallback when Claude Code's classifier
blocks an `agnes <verb>` invocation (e.g. `! agnes init …`).
- Setup script step 1 (no-CA install path) now emits a robust
`grep -qF + ||` snippet for the optional `~/.local/bin` PATH
persistence so re-runs don't append a duplicate entry to the
user's rc file (fixed-string match + short-circuit per the dedup
bug report).
## [0.55.0] — 2026-05-19
### Added
@ -133,6 +185,7 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
save) mirroring the Memory Domain pattern.
### Changed
<<<<<<< HEAD
- **Bulk-assign tables → package** modal — package dropdown options
now carry a `(N of M tables already in)` suffix so admins see the
existing distribution before picking a target. Counts surface
@ -442,6 +495,16 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
- Single PR cutover (no two-phase rollout). Legacy
`marketplace_plugins.is_system` + `user_plugin_optouts` retained
per spec D1 — Marketplace was deliberately not touched.
=======
<<<<<<< HEAD
- /home onboarding Step 2 retitled "turn on permission-skip for setup"
and now leads with `claude --dangerously-skip-permissions` as the
recommended session flag, because the Step 4 paste runs ~20 shell
commands that auto-accept-edits does not cover (Bash still prompts).
The flag is session-scoped, drops on next plain `claude`. Auto-accept
via Shift + Tab kept as the strict-review fallback for users who want
to approve each command; persistent YOLO setup link unchanged.
>>>>>>> 4c4e9e42 (fix(web): swap /home Steps 2↔3, claude --yolo as copy-button command)
## [0.54.29] — 2026-05-19
@ -496,6 +559,18 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
UI shows the corrected project). The orchestrator now compares the
two at every rebuild and, if they differ, calls
`rebuild_from_registry()` to regenerate the extract.
=======
- /home onboarding reordered: folder creation is now Step 2 (was
Step 3) and starting Claude with `claude --dangerously-skip-permissions`
is the new Step 3 (was the auto-mode step), rendered with the same
`.install-cmd` + copy-button affordance the other steps use. Step 4
paste runs ~20 shell commands that auto-accept-edits would not cover
(Bash still prompts), so the YOLO flag is the default recommendation;
session-scoped, drops on next plain `claude`. Shift + Tab → auto-
accept-edits kept as the strict-review fallback; persistent YOLO
allowlist link to /setup-advanced#yolo unchanged. Setup script's
"Verify cwd" warning copy refreshed to reference "/home Step 2".
>>>>>>> c195e0fa (fix(web): swap /home Steps 2↔3, claude --yolo as copy-button command)
- Setup script no longer auto-creates the workspace folder. Step 2 of
the pasted prompt now runs `pwd`, compares it to `$HOME/<workspace_dir>`
(the folder the /home page's visible Step 3 told the user to create

View file

@ -307,8 +307,13 @@ def _install_cli_lines(*, has_ca: bool, server_url_placeholder: str = "{server_u
"",
" If `agnes --version` fails after install because ~/.local/bin is not on PATH:",
" export PATH=\"$HOME/.local/bin:$PATH\"",
" # persist: append the same line to your ~/.zshrc or ~/.bashrc",
" # (the trust block in step 0 already does this for you on first run).",
" # Persist for future shells. Use `grep -qF` (fixed-string,",
" # not regex) + `||` short-circuit so a re-run doesn't append",
" # a duplicate. Pick the rc file your login shell reads:",
" RC=\"$HOME/.zshrc\" # or ~/.bashrc / ~/.bash_profile",
" grep -qF '$HOME/.local/bin' \"$RC\" 2>/dev/null \\",
" || echo 'export PATH=\"$HOME/.local/bin:$PATH\"' >> \"$RC\"",
" # (The trust block in step 0 already does this for you on first run.)",
]
return [
"1) Install the CLI:",
@ -319,7 +324,12 @@ def _install_cli_lines(*, has_ca: bool, server_url_placeholder: str = "{server_u
"",
" If `agnes --version` fails after install because ~/.local/bin is not on PATH:",
" export PATH=\"$HOME/.local/bin:$PATH\"",
" # persist: append the same line to your ~/.zshrc or ~/.bashrc",
" # Persist for future shells. Use `grep -qF` (fixed-string, not",
" # regex) + `||` short-circuit so a re-run doesn't append a",
" # duplicate. Pick the rc file your login shell reads:",
" RC=\"$HOME/.zshrc\" # or ~/.bashrc / ~/.bash_profile",
" grep -qF '$HOME/.local/bin' \"$RC\" 2>/dev/null \\",
" || echo 'export PATH=\"$HOME/.local/bin:$PATH\"' >> \"$RC\"",
]
@ -327,7 +337,7 @@ def _init_lines(server_url_placeholder: str = "{server_url}") -> list[str]:
"""Steps 2-4 — workspace folder check, then `agnes init` + smoke verify.
Step 2 verifies the user is already cd'd into the workspace folder
that the /home onboarding page's visible "Step 3 — create your
that the /home onboarding page's visible "Step 2 — create your
workspace folder" told them to create manually (`mkdir -p
~/{workspace_dir} && cd ~/{workspace_dir}`). The pasted script
DOES NOT auto-create the folder that would silently override an
@ -363,7 +373,7 @@ def _init_lines(server_url_placeholder: str = "{server_url}") -> list[str]:
return [
"",
"2) Verify the user is already in the workspace folder.",
" The /home page's visible \"Step 3 — create your workspace folder\"",
" The /home page's visible \"Step 2 — create your workspace folder\"",
" already asked the user to run",
" mkdir -p ~/{workspace_dir} && cd ~/{workspace_dir}",
" in their terminal BEFORE pasting this script. Do NOT silently",
@ -379,7 +389,7 @@ def _init_lines(server_url_placeholder: str = "{server_url}") -> list[str]:
" If `pwd` does NOT match, STOP and tell the user verbatim:",
"",
" \"You are in <current-pwd>, but {instance_brand} is normally",
" installed in ~/{workspace_dir} (see /home Step 3). Either run",
" installed in ~/{workspace_dir} (see /home Step 2). Either run",
" mkdir -p ~/{workspace_dir} && cd ~/{workspace_dir}",
" in your terminal now and re-paste this setup script, OR reply",
" 'install here' to install {instance_brand} in <current-pwd>",
@ -393,8 +403,25 @@ def _init_lines(server_url_placeholder: str = "{server_url}") -> list[str]:
" Do NOT run `mkdir`, do NOT `cd`, do NOT",
" continue to step 3.",
"",
"3) Bootstrap your {instance_brand} workspace in this directory:",
f" agnes init --server-url \"{server_url_placeholder}\" --token \"{{token}}\" --workspace .",
"3) Bootstrap your {instance_brand} workspace in this directory.",
" Write the PAT to a file FIRST, then run `agnes init` with",
" `--token-file`. Passing the JWT inline via `--token \"eyJ...\"`",
" sometimes trips Claude Code's auto-classifier (long bearer",
" token in a command line looks like a credential-exfil pattern);",
" piping the token through a file keeps it out of the command-",
" line argv entirely.",
"",
" mkdir -p ~/.agnes && umask 077 && cat > ~/.agnes/token <<'AGNES_PAT'",
"{token}",
"AGNES_PAT",
f" agnes init --server-url \"{server_url_placeholder}\" --token-file ~/.agnes/token --workspace .",
"",
" If Claude Code still blocks an `agnes` command (e.g. the",
" `agnes init` line above or `agnes catalog` in step 4), prefix",
" it with `!` to run the command directly in your shell,",
" bypassing the auto-classifier — e.g. `! agnes init …`. The",
" `!` prefix is Claude Code's escape hatch for commands you",
" explicitly trust.",
"",
" This authenticates with the PAT, fetches your CLAUDE.md (RBAC-filtered),",
" writes AGNES_WORKSPACE.md (human-facing docs), installs Claude Code",

View file

@ -1057,6 +1057,9 @@
<p class="lead">
{{ instance_brand }} gives <strong>Claude Code</strong> on your computer access to your team's <strong>curated data, plugins, third-party tools (Asana, Google Workspace, Atlassian), and shared knowledge</strong> — so you can ask questions and get answers in plain language, right from your terminal. This page walks you through the <strong>one-time setup (~10 minutes)</strong>; the install script also connects your tools for you, so there's no extra page to visit. Everything it installs lives in your home folder (<code style="background: rgba(255,255,255,0.12); padding: 1px 6px; border-radius: 4px; font-family: var(--hp-font-mono); font-size: 12.5px;">~/{{ workspace_dir }}</code>) and can be removed in one command.
</p>
<p class="lead lead-privacy">
<strong>What leaves your machine.</strong> Session telemetry — prompts, tool calls, and tool responses — flows back to the central catalog so the team can analyse failure patterns. Raw data rows you query locally stay on your machine; only the prompt/response transcript travels. Need a session off the record? Toggle Private in Claude Code (by typing <code style="background: rgba(255,255,255,0.12); padding: 1px 6px; border-radius: 4px; font-family: var(--hp-font-mono); font-size: 12.5px;">/agnes-private</code>) to disable telemetry for that chat — nothing from that session reaches the catalog.
</p>
<div class="install-block">
<div class="label">Step 1 — install Claude Code</div>
@ -1097,19 +1100,8 @@
</div>
</div>
{% if home_automode.show %}
<div class="install-block">
<div class="label">Step 2 — turn on auto-mode (recommended before Step 4)</div>
<div class="install-note">
In the Claude Code session you just signed into, press <strong>Shift + Tab</strong>. Claude cycles modes: default → <strong>auto-accept edits</strong> → plan mode → default; the footer shows <code>⏵⏵</code> when auto-accept is on. On the first cycle to auto-accept, Claude asks whether to make it the default — say <strong>yes</strong>. Closed the session already? Run <code>claude</code> again, then press <strong>Shift + Tab</strong>.
<br><br>
Want full auto-approve including Bash? See <a href="/setup-advanced#yolo">YOLO mode</a> on /setup-advanced — pairs <code>--dangerously-skip-permissions</code> with a reviewed <code>~/.claude/settings.local.json</code> allowlist. Skip if you're not sure.
</div>
</div>
{% endif %}
<div class="install-block">
<div class="label">Step 3 — create your workspace folder</div>
<div class="label">Step 2 — create your workspace folder</div>
<div class="os-tabs" role="tablist" aria-label="Operating system">
<button type="button" role="tab" class="os-tab is-active"
data-os-tab="unix" aria-selected="true">macOS / Linux / WSL</button>
@ -1126,10 +1118,28 @@ Set-Location "$HOME\{{ workspace_dir }}"</span>
<button class="copy-btn" data-copy-target="install-cmd-mkdir-windows">Copy</button>
</div>
<div class="install-note">
This is where {{ instance_brand }} will live. Run the command in the terminal you opened for Step 1, then keep that terminal handy — the next step pastes the setup script into Claude Code from this same directory.
This is where {{ instance_brand }} will live. Run the command in the terminal you opened for Step 1, then keep that terminal handy — Step 3 launches Claude Code from this same directory.
</div>
</div>
{% if home_automode.show %}
<div class="install-block">
<div class="label">Step 3 — start Claude Code with permission-skip (recommended before Step 4)</div>
<div class="install-note">
The Step 4 paste runs many shell commands (CLI install, workspace bootstrap, marketplace clone, MCP register, connector logins). Launch Claude Code from your Step 2 directory with this flag so the setup completes without ~20 Yes/No prompt approvals:
</div>
<div class="install-cmd">
<span class="multiline" id="install-cmd-claude-yolo">claude --dangerously-skip-permissions</span>
<button class="copy-btn" data-copy-target="install-cmd-claude-yolo">Copy</button>
</div>
<div class="install-note">
Session-scoped — drops on next plain <code>claude</code>. Safe here because the script you paste in Step 4 is generated by this server and ends after a fixed sequence; the flag does not weaken future Claude sessions. Prefer reviewing each command? Run plain <code>claude</code> and press <strong>Shift + Tab</strong> to cycle on <strong>auto-accept edits</strong> (default → auto-accept edits → plan mode; footer shows <code>⏵⏵</code>). Covers file edits, not Bash — expect ~20 prompt clicks during Step 4.
<br><br>
Persistent YOLO (allowlisted): see <a href="/setup-advanced#yolo" target="_blank" rel="noopener">YOLO mode</a> on /setup-advanced — pairs <code>--dangerously-skip-permissions</code> with a reviewed <code>~/.claude/settings.local.json</code> allowlist.
</div>
</div>
{% endif %}
<div class="install-block">
<div class="label">Step 4 — install {{ instance_brand }} from inside Claude Code</div>
<p class="setup-cta-lead">

View file

@ -87,6 +87,32 @@ _INIT_COMPLETE_FILE = ".claude/init-complete"
_CA_ENV_VARS = ("SSL_CERT_FILE", "REQUESTS_CA_BUNDLE", "GIT_SSL_CAINFO")
def _chmod_workspace_hooks(workspace: Path) -> None:
"""Set execute bit on every `.sh` under `<workspace>/.claude/hooks/`.
Claude Code's plugin install path doesn't always preserve the execute
bit on shell hook files depending on the archive format the plugin
ships in (zip, no-bit-preserving git checkout config, etc.), hooks
can land on disk as `rw-r--r--` and every fire returns Permission
denied. The user-visible symptom is a silent SessionStart / PreToolUse
failure that looks like the hooks just aren't installed.
Best-effort. No-op on Windows NTFS via Git Bash (chmod is meaningless
on NTFS without ACLs). Failures are swallowed a hook the user can
still read is no worse than the pre-fix baseline.
"""
hooks_dir = workspace / ".claude" / "hooks"
if not hooks_dir.is_dir():
return
for path in hooks_dir.rglob("*.sh"):
try:
current = path.stat().st_mode
# Add user/group/other execute. Same effect as `chmod +x`.
path.chmod(current | 0o111)
except OSError:
pass
def _is_windows_host() -> bool:
"""True when the Python interpreter sees Windows underneath.
@ -182,7 +208,25 @@ init_app = typer.Typer(help="Bootstrap an analyst workspace in this directory")
@init_app.callback(invoke_without_command=True)
def init(
server_url: str = typer.Option(..., "--server-url", help="Agnes server URL"),
token: str = typer.Option(..., "--token", help="Personal access token"),
token: Optional[str] = typer.Option(
None, "--token",
help=(
"Personal access token. Can also be supplied via the "
"AGNES_TOKEN env var or --token-file (see also). Inline "
"--token sometimes trips Claude Code's auto-classifier "
"(long bearer-token string in a command line); prefer "
"--token-file or AGNES_TOKEN to dodge that."
),
),
token_file: Optional[str] = typer.Option(
None, "--token-file",
help=(
"Path to a file whose first non-blank line is the PAT. Wins "
"over AGNES_TOKEN env when both are set; loses to an explicit "
"--token flag. The token never appears in the command string "
"this way, which dodges Claude Code's bearer-token classifier."
),
),
force: bool = typer.Option(False, "--force", help="Re-initialize an existing workspace"),
workspace_str: Optional[str] = typer.Option(None, "--workspace", help="Target dir (default: cwd)"),
skip_materialize: bool = typer.Option(
@ -200,6 +244,33 @@ def init(
workspace = Path(workspace_str).resolve() if workspace_str else Path.cwd()
server_url = server_url.rstrip("/")
# Resolve the token. Precedence: explicit --token > --token-file >
# AGNES_TOKEN env var > error. --token-file and AGNES_TOKEN exist so
# the analyst can paste an `agnes init --server-url … --token-file
# ~/.agnes/token` (or simply set the env) without Claude Code's
# auto-classifier flagging the long JWT in the command line.
if token is None and token_file:
try:
for line in Path(token_file).expanduser().read_text(encoding="utf-8").splitlines():
line = line.strip()
if line:
token = line
break
except OSError as exc:
typer.echo(render_error(0, {"detail": {
"kind": "partial_state",
"hint": f"--token-file {token_file!r} could not be read: {exc}",
}}), err=True)
raise typer.Exit(1)
if token is None:
token = os.environ.get("AGNES_TOKEN", "").strip() or None
if not token:
typer.echo(render_error(0, {"detail": {
"kind": "partial_state",
"hint": "Supply a token via --token, --token-file, or AGNES_TOKEN env var.",
}}), err=True)
raise typer.Exit(1)
# Best-effort cleanup before ANY TLS handshake fires below — stale
# SSL_CERT_FILE / REQUESTS_CA_BUNDLE / GIT_SSL_CAINFO pointers from a
# previous Agnes install on this host (or its Windows User-scope
@ -417,11 +488,12 @@ def init(
if not settings_path.exists():
settings_path.parent.mkdir(parents=True, exist_ok=True)
settings_path.write_text(json.dumps(
{"model": "sonnet", "permissions": {"allow": ["Read", "Bash", "Grep", "Glob"]}},
{"model": "sonnet", "permissions": {"allow": ["Read", "Bash", "Bash(agnes *)", "Grep", "Glob"]}},
indent=2,
), encoding="utf-8")
install_claude_hooks(workspace)
install_claude_commands(workspace)
_chmod_workspace_hooks(workspace)
# ------------------------------------------------------------------
# Step 6: CLAUDE.local.md stub — only when absent. `--force` does NOT

View file

@ -242,6 +242,19 @@ def _bootstrap_clone(token: str) -> bool:
except OSError:
pass
# Add execute bit to every `.sh` under the clone — git's checkout doesn't
# always preserve the file-mode bit (filemode=false repos, archive
# extractions), and Claude Code's later `plugin install` copies the
# files into the workspace `.claude/hooks/` AS-IS, so hooks that lost
# the +x bit here would fire with Permission denied. Fixing at the
# source (marketplace clone) means every downstream plugin install
# gets executable hooks for free. Best-effort: no-op on Windows NTFS.
for sh in CLONE_DIR.rglob("*.sh"):
try:
sh.chmod(sh.stat().st_mode | 0o111)
except OSError:
pass
if not _register_clone_with_claude(CLONE_DIR):
return False

View file

@ -1,6 +1,6 @@
[project]
name = "agnes-the-ai-analyst"
version = "0.55.0"
version = "0.55.1"
description = "Agnes — AI Data Analyst platform for AI analytical systems"
requires-python = ">=3.11,<3.14"
license = "MIT"

View file

@ -260,10 +260,14 @@ def test_home_automode_env_can_hide(fresh_db, monkeypatch):
def test_home_renders_automode_block_by_default(fresh_db, monkeypatch):
"""The auto-mode step renders by default for the not-onboarded /home
view. The block is now Step 2 (the install-flow reorder put auto-mode
BEFORE the Agnes install so users have auto-accept on for Step 3's
~20 commands), so its label is "Step 2 — turn on auto-mode"."""
"""The permission-mode step renders by default for the not-onboarded
/home view. The block is Step 3 (folder creation moved up to Step 2
so the user mkdir+cd's first, then this step launches Claude in that
directory with the right flag for Step 4's ~20 shell commands).
Label primarily recommends `claude --dangerously-skip-permissions`
via the standard `.install-cmd` + copy-button affordance; auto-
accept-edits via Shift + Tab kept as the strict fallback for users
who want to review each command."""
monkeypatch.delenv("AGNES_HOME_SHOW_AUTOMODE", raising=False)
from src.db import get_system_db, close_system_db
@ -277,10 +281,10 @@ def test_home_renders_automode_block_by_default(fresh_db, monkeypatch):
c = _client()
body = c.get("/home", cookies={"access_token": sess}).text
assert "Step 2 — turn on auto-mode" in body
# The auto-mode step now lives inside the install-hero as an
# install-block (peer with Step 1 + Step 3), not as a separate
# automode-card. Look for the label + the keystroke prompt.
assert "Step 3 — start Claude Code with permission-skip" in body
# Recommended path: `claude --dangerously-skip-permissions`.
assert "claude --dangerously-skip-permissions" in body
# Strict fallback: Shift + Tab → auto-accept-edits.
assert "Shift + Tab" in body
@ -298,7 +302,7 @@ def test_home_hides_automode_block_when_env_off(fresh_db, monkeypatch):
c = _client()
body = c.get("/home", cookies={"access_token": sess}).text
assert "Step 2 — turn on auto-mode" not in body
assert "Step 3 — start Claude Code with permission-skip" not in body
def test_navbar_home_link_uses_home_route(fresh_db, monkeypatch):

View file

@ -1033,8 +1033,8 @@ def test_step_2_checks_pwd_does_not_auto_mkdir():
assert "$HOME/Agnes" in joined # default workspace_dir
assert "~/Agnes" in joined
# Warning copy that references the /home Step 3 manual mkdir line.
assert "/home Step 3" in joined
# Warning copy that references the /home Step 2 manual mkdir line.
assert "/home Step 2" in joined
assert "mkdir -p ~/Agnes && cd ~/Agnes" in joined
# Explicit "install here" / "abort" decision tree.

View file

@ -104,8 +104,8 @@ def test_home_onboarded_user_sees_nav_hub(fresh_db):
# All four inline install-blocks are hidden post-onboarding — the
# labels rendered inside the install-block divs go away.
assert "Step 1 — install Claude Code" not in body
assert "Step 2 — turn on auto-mode" not in body
assert "Step 3 — create your workspace folder" not in body
assert "Step 2 — create your workspace folder" not in body
assert "Step 3 — start Claude Code with permission-skip" not in body
assert "Step 4 — install" not in body
@ -139,7 +139,7 @@ def test_connectors_section_removed_from_home(fresh_db):
# Auto-mode peer section still gone (legacy guard, not regressed).
assert 'class="automode-card"' not in body
assert 'data-section="step3"' not in body
assert "Step 2 — turn on auto-mode" not in body
assert "Step 3 — start Claude Code with permission-skip" not in body
# Dedicated connectors block is gone from /home in BOTH states.
assert 'class="connector-tiles"' not in body
assert 'data-section="connectors"' not in body