Skip to content

feat: mise/native tool install for engram + lean-ctx, agentflare run, abs-path MCP - #127

Merged
getappz merged 6 commits into
masterfrom
fix/init-mcp-setup
Jul 10, 2026
Merged

feat: mise/native tool install for engram + lean-ctx, agentflare run, abs-path MCP#127
getappz merged 6 commits into
masterfrom
fix/init-mcp-setup

Conversation

@getappz

@getappz getappz commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Dependency-light install + launch tooling for agentflare's integrations, plus MCP-registration robustness.

engram — install via mise, register by absolute path (5b0710b)

  • Bare command names (agentflare, engram) don't resolve for GUI-launched hosts lacking ~/.local/bin on PATH; engram had no dependency-free install without Go/Homebrew/npm.
  • Adds mise bootstrap (src/mise_install.rs) and installs engram via mise's github: backend (prebuilt release binary, checksum-verified — no toolchain). Registers every host's engram + agentflare MCP server against the resolved absolute path. For native engram hosts, engram setup is run via the mise path so it writes that absolute path (and installs the memory persona) itself. Honest engram check (plugin AND a real mcpServers.engram). Shares paths::agentflare_binary().

lean-ctx — native installer, not npm/mise (e8b2b13, cdb9eee, 0a2a05b)

  • Installs via lean-ctx's own prebuilt-binary installer, declared in a small data-driven registry (src/tool_install.rs): each tool lists native methods (curl | sh, brew) in priority order; the runner picks the first whose helper is present. No mise, no npm.
  • lean-ctx's onboard installs a shell hook that gates non-allowlisted commands (and blocks sh -c). Post-install, agentflare (via direct process spawns) allowlists agentflare + mise and sets compression_level = max (power mode). Without this, the gate would block agentflare's own re-invocations and mise usage under the default enforce mode.

agentflare run <agent> — mise env + wrangler-style .dev.vars (b0917c3)

  • Launches an agent through mise exec so all mise-managed tools are on PATH for the session and anything it spawns — makes mise tasks/tooling available inside the agent.
  • Injects wrangler-style .dev.vars (dotenv KEY=VALUE, # comments, quotes). --env <stage> loads .dev.vars.<stage>, which replaces the base file (matching wrangler).
  • src/dev_vars.rs (loader), src/agent_launch.rs::run_launch_env (env + mise wrap; run_launch delegates so agents launch is unchanged), src/cli/run.rs (subcommand).

refresh-devel mise task (6a1e1ce)

  • Drops the hardcoded .worktrees/devel dir so it builds whatever worktree it's run from.

Verification

  • engram/lean-ctx MCP ✔ Connected; agentflare run verified to inject .dev.vars values + all mise tool paths into a launched agent.
  • Full end-to-end: agentflare init installs lean-ctx natively, onboards, allowlists agentflare+mise, sets power mode.
  • Tests pass (dotenv parsing/staging, tool registry, launch engine).

Summary by CodeRabbit

  • New Features
    • Added a consent-gated installer component for mise and PATH-independent tool setup via absolute executables.
    • Introduced agentflare run CLI support with optional env/model/mode and stage-based .dev.vars loading.
    • Added improved agent launch behavior to optionally run through mise when available.
  • Bug Fixes
    • Improved engram install/verification and MCP server registration reliability across hosts (including Claude Code).
    • Made MCP registration more consistent by using absolute agentflare paths.
  • Tests
    • Updated component registry expectations to include the new mise component.

agentflare init didn't reliably set up the agentflare/engram MCP servers.
Bare command names (`agentflare`, `engram`) don't resolve for GUI-launched
hosts that lack ~/.local/bin on PATH, and engram had no dependency-free install
path on machines without Go/Homebrew/npm.

- add mise bootstrap (src/mise_install.rs): cross-platform detect-or-install of
  mise, used as the uniform, dependency-free way to provide the engram binary
- install engram through mise's github backend (prebuilt release binary,
  checksum-verified; no Go toolchain, no compile, no npm) — the only backend
  shipped; drop the old go install/brew path
- register every host's engram + agentflare MCP server against the resolved
  absolute path, so GUI-launched clients resolve them regardless of PATH.
  For native engram hosts, run `engram setup` via the mise path so it writes
  that absolute path (and installs the memory persona) itself
- engram check now requires the plugin AND a real mcpServers.engram entry,
  not just an enabled plugin
- share paths::agentflare_binary() between init hooks and MCP registration
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds cross-platform mise bootstrapping, mise-based engram and leanctx installation, absolute-path MCP registration, and a new run command that loads staged .dev.vars files and launches agents with environment overrides.

Changes

Mise-backed installation and registration

Layer / File(s) Summary
mise bootstrap and tool resolution
src/main.rs, src/mise_install.rs, mise.local.toml
Adds mise discovery, cross-platform installation, global tool activation, executable resolution, module registration, and task metadata updates.
engram and tool installation
src/engram_install.rs, src/tool_install.rs, src/components.rs
Routes engram and leanctx installation through mise or shared installer definitions, with component checks and validation updated accordingly.
component setup and MCP registration
src/components.rs
Adds the consent-gated mise component and uses absolute paths for engram and agentflare MCP registration across hosts.
shared executable path handling
src/paths.rs, src/init.rs
Centralizes the running agentflare binary path and current-directory resolution used during initialization.

Environment-aware agent run command

Layer / File(s) Summary
Staged dotenv loading
src/dev_vars.rs
Loads staged or base .dev.vars files and parses supported dotenv entries with tests.
Environment-aware launch execution
src/agent_launch.rs, src/agents.rs
Adds environment injection and optional mise-based execution to agent launching.
Run command CLI wiring
src/cli/mod.rs, src/cli/run.rs, src/main.rs
Adds the run subcommand, its arguments, dispatch, and module declarations.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI
  participant DevVars
  participant Agents
  participant Mise
  participant Agent

  User->>CLI: run agent [options]
  CLI->>DevVars: load(stage)
  DevVars-->>CLI: environment variables
  CLI->>Agents: cli_run(agent, env, model, mode, args)
  Agents->>Mise: mise exec -- binary
  Mise->>Agent: launch with environment and arguments
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is missing the required Summary, Test plan, and Notes for reviewers sections from the repository template. Add the template headings and fill in what changed, test commands/results, and reviewer notes on risks and backwards compatibility.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is specific and matches the main change set: mise/native installs, agentflare run, and absolute-path MCP registration.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/init-mcp-setup

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components.rs (1)

445-474: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

mark_done is called unconditionally — a failed (or undefined-host) registration is still marked "done".

mark_done(&marker) at Line 473 runs regardless of the match result, including the cline/opencode failed to write … paths and the _ => "no engram integration defined" arm. Because the non-claude check uses installed_via_mise() && host_marker("engram-setup", &host).exists(), the component will report satisfied on the next run even though MCP registration never succeeded. The native-host branch above (Line 433-438) correctly gates mark_done on success; this branch should too.

🐛 Proposed fix: gate the marker on success
-                    let result = match host.as_str() {
+                    let (result, ok) = match host.as_str() {
                         "cline" => {
                             let path = home().join(".cline").join("mcp.json");
                             if merge_json(&path, "engram", entry) {
-                                format!("{} (engram registered)", path.display())
+                                (format!("{} (engram registered)", path.display()), true)
                             } else {
-                                format!("failed to write {}", path.display())
+                                (format!("failed to write {}", path.display()), false)
                             }
                         }
                         "continue" => {
                             let path = cwd().join(".continue").join("mcpServers").join("engram.json");
                             if write_if_absent(&path, &(serde_json::to_string_pretty(&entry).unwrap() + "\n")) {
-                                format!("{} written", path.display())
+                                (format!("{} written", path.display()), true)
                             } else {
-                                format!("{} exists, skipped", path.display())
+                                (format!("{} exists, skipped", path.display()), true)
                             }
                         }
                         "opencode" => {
                             let path = home().join(".config").join("opencode").join("opencode.jsonc");
                             if merge_opencode_mcp(&path, "engram", entry) {
-                                format!("{} (engram registered)", path.display())
+                                (format!("{} (engram registered)", path.display()), true)
                             } else {
-                                format!("failed to write {}", path.display())
+                                (format!("failed to write {}", path.display()), false)
                             }
                         }
-                        _ => format!("no engram integration defined for host '{host}'"),
+                        _ => (format!("no engram integration defined for host '{host}'"), false),
                     };
-                    mark_done(&marker);
+                    if ok {
+                        mark_done(&marker);
+                    }
                     result
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components.rs` around lines 445 - 474, Gate mark_done(&marker) on
successful registration in the host match branch: treat successful
cline/continue/opencode writes as success, and leave the marker unset for failed
writes or the undefined-host arm. Preserve the existing result messages while
ensuring the marker is only created after a successful MCP registration,
matching the native-host branch behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mise_install.rs`:
- Around line 56-65: Update default_locations() to include the WinGet and Scoop
Windows executable paths in addition to %LOCALAPPDATA%\mise\bin\mise.exe, so
mise_bin() can find installations performed by install_windows() and avoid
reporting failure.

---

Outside diff comments:
In `@src/components.rs`:
- Around line 445-474: Gate mark_done(&marker) on successful registration in the
host match branch: treat successful cline/continue/opencode writes as success,
and leave the marker unset for failed writes or the undefined-host arm. Preserve
the existing result messages while ensuring the marker is only created after a
successful MCP registration, matching the native-host branch behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 282a0bee-b1a6-4145-bb3e-008c4cb67c22

📥 Commits

Reviewing files that changed from the base of the PR and between 737af7a and 5b0710b.

📒 Files selected for processing (6)
  • src/components.rs
  • src/engram_install.rs
  • src/init.rs
  • src/main.rs
  • src/mise_install.rs
  • src/paths.rs

Comment thread src/mise_install.rs
Comment on lines +56 to +65
fn default_locations() -> Vec<PathBuf> {
if cfg!(windows) {
let local = std::env::var("LOCALAPPDATA")
.map(PathBuf::from)
.unwrap_or_else(|_| home().join("AppData").join("Local"));
vec![local.join("mise").join("bin").join("mise.exe")]
} else {
vec![home().join(".local").join("bin").join("mise")]
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm default winget/scoop install locations for mise on Windows.

Repository: getappz/agentflare

Length of output: 156


🌐 Web query:

mise winget scoop install location windows binary path

💡 Result:

On Windows, the installation locations for mise, Scoop, and WinGet depend on their default configurations, though these can be customized. mise Installation and Shims By default, mise installs tools into %LOCALAPPDATA%\mise\installs (or ~/.local/share/mise/installs) [1]. Because mise uses a shim-based approach on Windows rather than modifying the PATH directly, it requires the directory containing these shims to be included in your PATH [2][3][4]. By default, this shims directory is located at %LOCALAPPDATA%\mise\shims [2][5]. Scoop Installation Scoop, which is a recommended way to install mise on Windows, defaults to installing itself and its managed applications in the user's home directory [6][7]. - Root Directory: Defaults to %USERPROFILE%\scoop (can be overridden by the SCOOP environment variable) [6][8]. - Applications: Installed in %USERPROFILE%\scoop\apps [6]. - Shims: Scoop automatically creates shims for applications and adds them to your PATH [6][7]. These are stored in %USERPROFILE%\scoop\shims [6]. WinGet Installation WinGet (Windows Package Manager) typically installs applications into standard system or user-specific program directories, depending on the package manifest [2][9]. When using WinGet to install mise (winget install jdx.mise), it follows standard WinGet behavior, but users often need to manually ensure the mise shims directory (%LOCALAPPDATA%\mise\shims) is added to the PATH for mise to function correctly, as WinGet may not automatically configure this shim path [10][3][4]. Summary Table Package Manager | Default Root/Base Path | Binary/Shim Path --- | --- | --- mise | %LOCALAPPDATA%\mise | %LOCALAPPDATA%\mise\shims [2][4] Scoop | %USERPROFILE%\scoop [6][8] | %USERPROFILE%\scoop\shims [6] WinGet | Varies by package [2] | Varies; manual setup often required for shims [3] Note: You can override these defaults by setting environment variables (e.g., SCOOP or MISE_INSTALLS_DIR) [1][11][8].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '== file list ==\n'
git ls-files src/mise_install.rs src | sed -n '1,120p'

printf '\n== outline src/mise_install.rs ==\n'
ast-grep outline src/mise_install.rs --view expanded || true

printf '\n== locate relevant symbols ==\n'
rg -n "default_locations|ensure_mise|mise_bin|install_windows|winget|scoop|LOCALAPPDATA|PATH" src/mise_install.rs src -n -S || true

printf '\n== src/mise_install.rs excerpt ==\n'
nl -ba src/mise_install.rs | sed -n '1,240p'

Repository: getappz/agentflare

Length of output: 8789


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '== src/mise_install.rs lines 1-240 ==\n'
sed -n '1,240p' src/mise_install.rs

Repository: getappz/agentflare

Length of output: 7683


🌐 Web query:

jdx.mise winget scoop Windows install path shims default location

💡 Result:

On Windows, the default location for mise shims is %LOCALAPPDATA%\mise\shims [1][2]. Mise supports both Scoop and Winget as installation methods on Windows [3]. When you install tools via mise, it populates this shims directory with small executables that act as symlinks to the mise binary, allowing for seamless command interception and version management [2]. To ensure that your shell can locate these tools, you should add the shims directory to your PATH environment variable [2]. If you use Scoop, it is generally designed to handle PATH configuration automatically [3]. For other installation methods or custom setups, you may need to add %LOCALAPPDATA%\mise\shims manually to your PATH or use the mise activate --shims command in your shell profile (such as your PowerShell profile) to manage the integration [2][4].

Citations:


🌐 Web query:

jdx.mise winget manifest install location scoop manifest path mise.exe

💡 Result:

The installation location for mise on Windows depends on the package manager used [1]. For WinGet, mise is typically installed in a subfolder within the WinGet package directory [2]: %LOCALAPPDATA%\Microsoft\WinGet\Packages\jdx.mise_Microsoft.Winget.Source_8wekyb3d8bbwe\mise\bin\mise.exe [2] WinGet also creates symlinks in: %LOCALAPPDATA%\Microsoft\WinGet\Links\mise.exe [2] For Scoop, mise is installed within the Scoop directory structure, typically under: %SCOOP%\apps\mise\current\bin\mise.exe Note that Scoop manages its own environment, and recent updates have decoupled the automatic activation of shims, requiring users to manually configure their PATH or use mise activate [3]. General installation behavior for mise on Windows: - Data and configuration: By default, mise uses %LOCALAPPDATA%\mise for data and shims [4][1][5]. - Shims: mise shims are typically located at %LOCALAPPDATA%\mise\shims [1][5]. - Customization: Users can override these defaults by setting environment variables such as MISE_DATA_DIR, MISE_CONFIG_DIR, and MISE_INSTALLS_DIR [4][6]. Setting MISE_INSTALLS_DIR to a shorter path (e.g., C:\mise) is sometimes recommended to avoid issues with long file paths on Windows [6].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '300,335p' src/components.rs

Repository: getappz/agentflare

Length of output: 2206


Windows install lookup misses WinGet/Scoop paths
default_locations() only checks %LOCALAPPDATA%\mise\bin\mise.exe, so a successful install_windows() can still fall through to MiseOutcome::Failed when mise_bin() rechecks PATH/defaults. Add the WinGet/Scoop install locations here, or return Installed after a successful package-manager install with a “open a new shell” note.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mise_install.rs` around lines 56 - 65, Update default_locations() to
include the WinGet and Scoop Windows executable paths in addition to
%LOCALAPPDATA%\mise\bin\mise.exe, so mise_bin() can find installations performed
by install_windows() and avoid reporting failure.

shiva added 5 commits July 10, 2026 19:53
… in its shell hook

Replace the npm/mise path for lean-ctx with its official prebuilt-binary
installer, declared in a small data-driven registry (src/tool_install.rs):
each tool lists native install methods (curl | sh, brew) in priority order and
the runner picks the first whose helper is present. No mise, no npm.

lean-ctx's onboard installs a shell hook that gates non-allowlisted commands —
including agentflare's own re-invocations — and also blocks `sh -c` outright.
So after install agentflare runs `lean-ctx allow agentflare` as a direct
process spawn (not via a shell), or it would lock itself out of every hooked
shell. Also corrects the now-stale mise component comment (mise is only the
installer for engram's prebuilt binary; lean-ctx no longer uses it).
…ed devel dir

Drop the hardcoded dir = .worktrees/devel so the task installs whatever branch/worktree it is run from (mise runs a dir-less task in its own config_root, which for a per-worktree tracked config is that worktree).
…rs env injection

Launches an agent (e.g. claude-code) via `mise exec` so all mise-managed
tools are on PATH for the session and anything it spawns — makes mise tasks and
tooling available inside the agent. Also injects wrangler-style .dev.vars:
dotenv KEY=VALUE with # comments and quotes; --env <stage> loads
.dev.vars.<stage>, which REPLACES the base .dev.vars (matching wrangler).

- src/dev_vars.rs: .dev.vars loader + minimal dotenv parser (unit-tested)
- src/agent_launch.rs: run_launch_env() injects env + wraps in `mise exec`;
  run_launch() delegates to it, so existing `agents launch` is unchanged
- src/agents.rs: cli_run() loads .dev.vars from cwd and reports what it injects
- src/cli/run.rs: the `run` subcommand
agentflare installs engram through mise and `agentflare run` launches via it, but mise isn't in lean-ctx's built-in default allowlist — so its onboarded gate would block mise (and thus agentflare's own mise usage) under the default enforce mode. Allow it alongside agentflare in the same post-install call.
The reason to run lean-ctx is denser model output; default it to the strongest compression during onboarding rather than leaving it at lite.
@getappz getappz changed the title fix: install engram via mise + register MCP servers by absolute path feat: mise/native tool install for engram + lean-ctx, agentflare run, abs-path MCP Jul 10, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/agent_launch.rs (1)

29-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test coverage for via_mise=true or env override injection.

Existing tests only exercise the via_mise=false path (via run_launch). The new mise-wrapping and env-injection logic — the core behavior added by this PR — has no direct test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agent_launch.rs` around lines 29 - 75, Add focused tests for
run_launch_env covering via_mise=true and environment override injection: verify
mise_bin is used with the expected “exec -- <binary>” arguments, and verify
supplied env entries are applied to the spawned command. Use test doubles or a
controlled executable/script to capture invocation and environment, while
retaining coverage for the existing non-mise path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/agent_launch.rs`:
- Around line 59-75: Update the error handling around cmd.status() in the agent
launch function to report the actual executable being spawned: use “mise” when
via_mise is true and the agent binary otherwise, while retaining the original
error details. Reference the mise command construction and downstream Err
handler so the message accurately identifies the failing launcher.

In `@src/components.rs`:
- Around line 337-351: Only persist the lean-ctx installation marker after a
successful install: update the closure under the apply component in
src/components.rs to write the log within the Ok branch of the
tool_install::install result, while leaving failed outcomes unmarked so
subsequent agentflare init attempts can retry.

---

Nitpick comments:
In `@src/agent_launch.rs`:
- Around line 29-75: Add focused tests for run_launch_env covering via_mise=true
and environment override injection: verify mise_bin is used with the expected
“exec -- <binary>” arguments, and verify supplied env entries are applied to the
spawned command. Use test doubles or a controlled executable/script to capture
invocation and environment, while retaining coverage for the existing non-mise
path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5e1e185f-c97b-4ee0-9644-04d63eac8014

📥 Commits

Reviewing files that changed from the base of the PR and between 5b0710b and 0a2a05b.

📒 Files selected for processing (9)
  • mise.local.toml
  • src/agent_launch.rs
  • src/agents.rs
  • src/cli/mod.rs
  • src/cli/run.rs
  • src/components.rs
  • src/dev_vars.rs
  • src/main.rs
  • src/tool_install.rs

Comment thread src/agent_launch.rs
Comment on lines +59 to +75
// `mise exec -- <binary> …` runs the agent inside mise's environment, so its
// tool paths are on PATH for the agent and its child shells.
let mise = if via_mise { crate::mise_install::mise_bin() } else { None };
let mut cmd = match &mise {
Some(m) => {
let mut c = Command::new(m);
c.arg("exec").arg("--").arg(&binary);
c
}
None => Command::new(&binary),
};
cmd.stdout(Stdio::inherit());
cmd.stderr(Stdio::inherit());
cmd.stdin(Stdio::inherit());
for (k, v) in env {
cmd.env(k, v);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Error message misattributes failures when launched via mise.

Once the mise branch is taken, a spawn failure at cmd.status() may originate from invoking mise itself, but the downstream Err(e) handler still always reports "failed to launch {binary}: {e}", which is misleading for debugging.

🐛 Proposed fix
     match cmd.status() {
         Ok(s) if s.success() => LaunchOutcome::Launched,
         Ok(s) => {
             let code = s.code().unwrap_or(-1);
             std::process::exit(code);
         }
-        Err(e) => LaunchOutcome::NotFound(format!(
-            "failed to launch {}: {e}",
-            binary.display()
-        )),
+        Err(e) => {
+            let target = mise.as_ref().map(|m| m.display().to_string()).unwrap_or_else(|| binary.display().to_string());
+            LaunchOutcome::NotFound(format!("failed to launch {target}: {e}"))
+        }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// `mise exec -- <binary> …` runs the agent inside mise's environment, so its
// tool paths are on PATH for the agent and its child shells.
let mise = if via_mise { crate::mise_install::mise_bin() } else { None };
let mut cmd = match &mise {
Some(m) => {
let mut c = Command::new(m);
c.arg("exec").arg("--").arg(&binary);
c
}
None => Command::new(&binary),
};
cmd.stdout(Stdio::inherit());
cmd.stderr(Stdio::inherit());
cmd.stdin(Stdio::inherit());
for (k, v) in env {
cmd.env(k, v);
}
Err(e) => {
let target = mise
.as_ref()
.map(|m| m.display().to_string())
.unwrap_or_else(|| binary.display().to_string());
LaunchOutcome::NotFound(format!("failed to launch {target}: {e}"))
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agent_launch.rs` around lines 59 - 75, Update the error handling around
cmd.status() in the agent launch function to report the actual executable being
spawned: use “mise” when via_mise is true and the agent binary otherwise, while
retaining the original error details. Reference the mise command construction
and downstream Err handler so the message accurately identifies the failing
launcher.

Comment thread src/components.rs
Comment on lines 337 to 351
apply: {
let log = leanctx_log.clone();
Box::new(move || {
if log.exists() {
return format!("lean-ctx install already triggered — check {}", log.display());
}
let _ = fs::create_dir_all(log.parent().unwrap());
let cmd = "npm install -g lean-ctx-bin && lean-ctx onboard";
let result = if cfg!(windows) {
Command::new("cmd").args(["/c", cmd]).status()
} else {
Command::new("sh").args(["-c", cmd]).status()
};
let outcome = crate::tool_install::install(&crate::tool_install::LEAN_CTX);
let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now()));
match result {
Ok(s) if s.success() => "lean-ctx installed and onboarded".to_string(),
_ => "lean-ctx install failed — run manually: npm install -g lean-ctx-bin && lean-ctx onboard".to_string(),
match outcome {
Ok(m) => format!("{m} + onboarded"),
Err(e) => e,
}
})
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

A failed lean-ctx install can never be retried.

The log is written unconditionally after install(...) (Line 345), and the early guard returns on log.exists() (Lines 340-342). So if the installer fails once, every subsequent agentflare init short-circuits to "already triggered" while check (via tool_install::installed) still reports the tool absent — leaving the component permanently unsatisfiable until the user manually deletes the log. Write the marker only on success.

🔒️ Proposed fix: persist the marker only on success
                     let _ = fs::create_dir_all(log.parent().unwrap());
                     let outcome = crate::tool_install::install(&crate::tool_install::LEAN_CTX);
-                    let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now()));
                     match outcome {
-                        Ok(m) => format!("{m} + onboarded"),
+                        Ok(m) => {
+                            let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now()));
+                            format!("{m} + onboarded")
+                        }
                         Err(e) => e,
                     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
apply: {
let log = leanctx_log.clone();
Box::new(move || {
if log.exists() {
return format!("lean-ctx install already triggered — check {}", log.display());
}
let _ = fs::create_dir_all(log.parent().unwrap());
let cmd = "npm install -g lean-ctx-bin && lean-ctx onboard";
let result = if cfg!(windows) {
Command::new("cmd").args(["/c", cmd]).status()
} else {
Command::new("sh").args(["-c", cmd]).status()
};
let outcome = crate::tool_install::install(&crate::tool_install::LEAN_CTX);
let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now()));
match result {
Ok(s) if s.success() => "lean-ctx installed and onboarded".to_string(),
_ => "lean-ctx install failed — run manually: npm install -g lean-ctx-bin && lean-ctx onboard".to_string(),
match outcome {
Ok(m) => format!("{m} + onboarded"),
Err(e) => e,
}
})
},
apply: {
let log = leanctx_log.clone();
Box::new(move || {
if log.exists() {
return format!("lean-ctx install already triggered — check {}", log.display());
}
let _ = fs::create_dir_all(log.parent().unwrap());
let outcome = crate::tool_install::install(&crate::tool_install::LEAN_CTX);
match outcome {
Ok(m) => {
let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now()));
format!("{m} + onboarded")
}
Err(e) => e,
}
})
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components.rs` around lines 337 - 351, Only persist the lean-ctx
installation marker after a successful install: update the closure under the
apply component in src/components.rs to write the log within the Ok branch of
the tool_install::install result, while leaving failed outcomes unmarked so
subsequent agentflare init attempts can retry.

@getappz
getappz merged commit 3961e55 into master Jul 10, 2026
10 checks passed
@getappz
getappz deleted the fix/init-mcp-setup branch July 10, 2026 17:01
getappz added a commit that referenced this pull request Jul 16, 2026
* refactor(update): split self-update into module + MCP-safe binary swap

Split single-file src/update.rs into src/update/{mod,github,swap}.rs.

swap.rs is the reusable MCP-safe binary-replacement primitive:
- never signals/kills any process, so a live `agentflare mcp` server keeps
  running its loaded image and picks up the new binary on next launch
- Windows: rename-aside + copy, with rollback on failure and a deferred
  .bat fallback when the exe is hard-locked against renaming
- Unix: same-fs staged atomic rename
- find_killable_pids() reports (never kills) other running instances

github.rs isolates release discovery/download/checksum, with pure
parse_checksum/verify_checksum helpers now unit-tested.

Prepares update::swap::replace_binary for reuse by dev-install (#127).

* feat(dev-install): build-from-source + atomic install over running binary

New `agentflare dev-install` subcommand: cargo build (release by default),
resolve the built binary via `cargo metadata` (honors CARGO_TARGET_DIR and
workspace shared targets), verify it answers `--version` under a timeout, then
swap it over the running binary using the MCP-safe update::swap::replace_binary
primitive (#122) — so a live `agentflare mcp` server is never disturbed.

- refuses to overwrite the build output itself (guards against running from the
  freshly built binary instead of the installed one)
- --debug builds debug; --dry-run reports the swap without performing it
- pure cargo-metadata target-dir parsing + same-file guard are unit-tested

* fix(dev-install): resolve built binary via cargo JSON, not target/<profile>

CodeRabbit (PR #206): built_binary_path assumed target_directory/<profile>/,
which is wrong when build.target / CARGO_BUILD_TARGET adds a <triple>/ segment
(or a custom profile renames the dir) -- the lookup would miss the binary.

Read the executable path from cargo's compiler-artifact JSON message instead of
reconstructing it, so any target/profile layout is handled. build_and_locate()
replaces the target-dir/profile-dir reconstruction and its parser.

* fix(update): address CodeRabbit review — swap rollback, staging race, net timeout

PR #206 CodeRabbit findings on the #122 swap/github code:
- swap.rs: surface Windows rollback failure (and the recoverable old-binary
  path) instead of swallowing it, honoring the "never leave without a binary"
  invariant.
- swap.rs: pid-scope the Unix staging filename so concurrent swaps against the
  same target cannot clobber each other's staged file.
- github.rs: give the release HTTP client connect + per-read timeouts so a hung
  network cannot block an update indefinitely (no overall timeout, to avoid
  capping large asset downloads).

* fix(dev-install): reject non-host CARGO_BUILD_TARGET; reap cargo on read error

CodeRabbit (PR #206) on build_and_locate:
- Reject a non-host CARGO_BUILD_TARGET early with a clear message: dev-install
  replaces the running binary, so a cross target would build something that
  cannot run here. verify_runs() remains the backstop for a .cargo/config
  build.target.
- Always child.wait() even when reading cargo stdout fails, so a failed read
  never orphans the cargo process.
getappz pushed a commit that referenced this pull request Aug 15, 2026
Agentflare-Agent: opencode
Agentflare-Branch: task/127-bwrap-sandbox-has-no-writable-bind-for-c
Agentflare-Item: 127
getappz added a commit that referenced this pull request Aug 15, 2026
#127) (#508)

* fix(jobs): bind claude-code's ~/.claude writable in bwrap sandbox (item #127)

Agentflare-Agent: opencode
Agentflare-Branch: task/127-bwrap-sandbox-has-no-writable-bind-for-c
Agentflare-Item: 127

* fix(jobs): rustfmt the claude-dir bwrap tests (item #127)

Agentflare-Agent: opencode
Agentflare-Branch: task/127-bwrap-sandbox-has-no-writable-bind-for-c
Agentflare-Item: 127

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>
getappz added a commit that referenced this pull request Aug 17, 2026
…dbox crate (#541)

Move agentflare-jobs's bwrap sandbox module into its own crate,
flare-sandbox, and make it agent-agnostic: instead of hardcoded
is_opencode/is_claude_code/is_cursor checks and three near-identical mount
blocks, it now takes a caller-supplied SandboxConfig (AgentProfile list +
writable_home_dirs) and applies whichever agent-state mounts match the
resolved command. agentflare-jobs's own sandbox.rs becomes the thin
adapter that supplies agentflare's concrete policy.

Cross-referenced akitaonrails/ai-jail's own per-agent state-dir table
(cloned into .refs/ai-jail for reference) for which $HOME directories each
CLI needs -- adopting its coverage of codex (.codex), gemini (.gemini),
aider (.aider), grok (.grok), kimi (.kimi-code), and opencode's second
directory (.config/opencode, alongside the existing .local/share/opencode)
-- but keeping agentflare's own ephemeral-overlay write policy (items
#106/#127) rather than ai-jail's persistent bind, since the two tools have
different containment goals.

No behavior change for claude-code/opencode/cursor; adds coverage for
codex/gemini/aider/grok/kimi, none of which had any agent-specific mount
before.

Agentflare-Agent: claude-code
Agentflare-Branch: feat/flare-sandbox-crate

Co-authored-by: shiva <shiva@gosysinfo.tech>
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