Skip to content

feat(adapters): add Factory controls and host integrations - #64

Merged
DevVig merged 4 commits into
mainfrom
feat/conductor-factory-effort
Jul 20, 2026
Merged

feat(adapters): add Factory controls and host integrations#64
DevVig merged 4 commits into
mainfrom
feat/conductor-factory-effort

Conversation

@DevVig

@DevVig DevVig commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • add one-click Factory lifecycle hooks plus official JSON-RPC interrupt and model-aware reasoning-effort control
  • attribute Synara and Conductor sessions through the built-in Codex/Claude watchers
  • open paired T3 Code threads with its official semantic deep link
  • bundle microbridgectl in signed app releases and prepare v0.3.0
  • add a repeatable macOS build/run/verify entrypoint

Capability boundaries

  • T3 effort remains disabled until its paired contract publishes provider option descriptors
  • Conductor is lifecycle attribution only because its public API cannot reliably map underlying journal ids or update active effort
  • no private databases, Electron scraping, or synthesized key presses

Verification

  • make ci
  • cargo test --manifest-path apps/microbridge-ui/src-tauri/Cargo.toml
  • cargo clippy --manifest-path apps/microbridge-ui/src-tauri/Cargo.toml --all-targets -- -D warnings
  • ./script/build_and_run.sh --verify
  • inspected the v0.3.0 debug app bundle: microbridge-ui, microbridged, and microbridgectl are native arm64 executables

Release

After merge, tag v0.3.0 to build the signed/notarized DMGs, updater artifacts, daemon archives, and Homebrew bump.

Summary by CodeRabbit

  • New Features
    • Added Factory integration with one-click hook setup, lifecycle status, interrupt controls, and model-aware reasoning settings.
    • Added Conductor and Synara session attribution without pairing codes or extra background processes.
    • T3 Code can now open the active thread using its official deep link.
  • Improvements
    • macOS packages now include all required Microbridge components.
    • Updated adapter settings and status messaging for the expanded integrations.
  • Documentation
    • Added installation, integration, architecture, and v0.3.0 release guidance.

DevVig added 3 commits July 20, 2026 15:46
Add official Factory lifecycle hooks plus on-demand JSON-RPC interrupt and model-aware effort control. Attribute Synara and Conductor sessions through existing journals, open T3 threads through its published deep link, and bundle the hook helper in release apps.
Build both daemon sidecars, bundle a real debug Tauri app, and expose run, verify, debug, and log modes through one project-local command and Codex Run action.
Align Rust, Tauri, and npm package versions and document the adapter capability boundaries and verification evidence for the 0.3.0 release.
Copilot AI review requested due to automatic review settings July 20, 2026 19:48
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d6cc4133-5dbf-4b94-ae30-e13bce693b65

📥 Commits

Reviewing files that changed from the base of the PR and between 81a3e00 and 0c3aa8a.

📒 Files selected for processing (1)
  • crates/microbridged/src/factory.rs
📝 Walkthrough

Walkthrough

Microbridge 0.3.0 adds Factory hooks, lifecycle ingestion, Droid JSON-RPC control, expanded Conductor and Synara attribution, T3 thread deep-link focus, updated UI integration management, and macOS build packaging for both native sidecars.

Changes

Factory and release integration

Layer / File(s) Summary
Release metadata and macOS build flow
.codex/environments/environment.toml, Cargo.toml, .github/workflows/release.yml, script/build_and_run.sh, apps/microbridge-ui/..., docs/releases/...
Versions move to 0.3.0; release and development builds compile and bundle both microbridged and microbridgectl.
Factory installation and UI synchronization
apps/microbridge-ui/src-tauri/src/lib.rs, apps/microbridge-ui/src/lib/bus.ts, apps/microbridge-ui/src/surfaces/*
Factory helper installation, atomic hook merging, cleanup, configuration synchronization, demo data, settings text, and UI tests are added.
Factory lifecycle ingestion and action control
crates/microbridgectl/src/main.rs, crates/microbridged/src/factory.rs, crates/microbridged/src/{main.rs,state.rs,lib.rs}, crates/mb-protocol/src/lib.rs
Factory events become lifecycle sessions, while daemon actions invoke Droid through streamed JSON-RPC with interrupt and reasoning-level handling.
Host attribution and T3 thread focus
crates/mb-adapters/src/*, crates/microbridged/src/{app_match.rs,t3code.rs}, adapters/t3code/README.md
Conductor and Factory labels are recognized, and T3 focused-thread actions use environment-aware official deep links.
Integration and capability documentation
README.md, INSTALL.md, adapters/*, docs/*
Factory installation, Conductor/Synara attribution, T3 pairing, consent boundaries, architecture constraints, and installed paths are documented.

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

Sequence Diagram(s)

sequenceDiagram
  participant Factory
  participant microbridgectl
  participant microbridged
  participant Droid
  Factory->>microbridgectl: Send lifecycle hook JSON
  microbridgectl->>microbridged: Ingest Factory session status
  microbridged->>Droid: Issue JSON-RPC action
  Droid-->>microbridged: Return streamed acknowledgement
Loading

Possibly related PRs

  • DevVig/microbridge#39: Extends Claude SDK host-labeling behavior for Conductor, overlapping with the new Conductor attribution logic.

Suggested reviewers: copilot

Poem

I’m a rabbit with hooks in a row,
Factory lights blink, then Droid starts to go.
Conductor hops into journal view,
T3 threads open with links bright and true.
Sidecars are bundled, the release winds chime—
Microbridge burrows into version zero-three time!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches a major part of the PR: adding Factory controls and host integrations.
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.

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

Copilot AI 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.

Pull request overview

This PR expands Microbridge’s first-party host support and release tooling by adding Factory lifecycle + JSON-RPC controls, attributing Synara/Conductor sessions via existing watchers, enabling semantic deep-link focus for T3 Code, bundling microbridgectl into app releases, and bumping the project to v0.3.0.

Changes:

  • Add Factory integration (managed hooks installer + on-demand Droid JSON-RPC interrupt and reasoning-effort controls).
  • Improve host attribution and focus handling (Synara/Conductor attribution; T3 Code thread deep-link focus).
  • Prepare v0.3.0 release assets and developer workflow (bundled microbridgectl, new build/run script, docs/version bumps).

Reviewed changes

Copilot reviewed 33 out of 36 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
script/build_and_run.sh Adds a repeatable macOS dev build/run/verify entrypoint that bundles both sidecars.
README.md Updates supported hosts/status to v0.3.x and documents Factory/Synara/Conductor behavior.
INSTALL.md Documents Factory hook installation/removal paths and prerequisites.
docs/releases/v0.3.0.md Adds v0.3.0 release notes covering new integrations and verification.
docs/protocol.md Updates focused-app key source documentation to include Conductor/Factory.
docs/architecture.md Updates architecture/footprint notes to include Factory + host attribution watchers.
docs/adapters.md Updates adapter strategy guidance to include Factory hooks + JSON-RPC.
crates/microbridged/src/t3code.rs Adds environment id tracking and semantic deep-link focus-open support.
crates/microbridged/src/state.rs Enhances lifecycle ingestion to associate internal owners/capabilities; adds Factory diagnostics and new adapter cards.
crates/microbridged/src/main.rs Installs/spawns the new internal Factory adapter action loop.
crates/microbridged/src/lib.rs Exposes the new factory module.
crates/microbridged/src/factory.rs Implements on-demand Droid JSON-RPC control + settings discovery for Factory sessions.
crates/microbridged/src/app_match.rs Adds app-family matching for Conductor and Factory.
crates/microbridgectl/src/main.rs Adds factory-event hook entrypoint for ingesting Factory lifecycle events.
crates/mb-protocol/src/lib.rs Adds Factory to default adapter preferences and consent documentation.
crates/mb-adapters/src/hosts.rs Adds Conductor workspace path → host attribution mapping.
crates/mb-adapters/src/codex.rs Attributes Codex sessions to Conductor/Factory via host metadata and cwd mapping.
crates/mb-adapters/src/claude.rs Attributes Claude sessions to Conductor via cwd mapping.
Cargo.toml Bumps workspace to 0.3.0 and enables Tokio process feature.
Cargo.lock Updates crate versions to 0.3.0.
apps/microbridge-ui/src/surfaces/surfaces.test.tsx Updates UI tests for Factory adapter preference and copy changes.
apps/microbridge-ui/src/surfaces/Settings.tsx Updates adapter UX copy and button labels for Factory/Synara/Conductor/T3.
apps/microbridge-ui/src/lib/bus.ts Updates demo snapshot to include Conductor/Synara/Factory cards.
apps/microbridge-ui/src-tauri/tauri.conf.json Bumps to 0.3.0 and bundles microbridgectl as an external binary.
apps/microbridge-ui/src-tauri/src/lib.rs Implements Factory hook merge/install/remove + enable/forget wiring in the UI backend.
apps/microbridge-ui/src-tauri/Cargo.toml Bumps UI crate version to 0.3.0.
apps/microbridge-ui/src-tauri/Cargo.lock Updates UI lockfile versions to 0.3.0.
apps/microbridge-ui/package.json Bumps UI package version to 0.3.0.
apps/microbridge-ui/package-lock.json Updates UI lockfile version to 0.3.0.
adapters/t3code/README.md Documents T3 network access requirement and new deep-link focus behavior.
adapters/synara/README.md Adds Synara integration documentation (host attribution via watchers).
adapters/README.md Updates adapter matrix/statuses to include Factory/Synara/Conductor and Rust-owned T3 adapter.
adapters/factory/README.md Adds Factory integration documentation (hooks + JSON-RPC controls).
adapters/conductor/README.md Adds Conductor integration documentation (watcher-based attribution only).
.github/workflows/release.yml Bundles microbridgectl into release builds and UI artifacts.
.codex/environments/environment.toml Adds a Codex environment action to run the new build/run script.
Files not reviewed (1)
  • apps/microbridge-ui/package-lock.json: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +386 to +392
for event in FACTORY_HOOK_EVENTS {
let groups = hooks
.entry((*event).to_string())
.or_insert_with(|| serde_json::json!([]));
let groups = groups.as_array_mut().ok_or_else(|| {
format!("Factory {event} hooks are not an array; preserving them unchanged.")
})?;
let method_and_params = match action {
Action::Interrupt => ("droid.interrupt_session", json!({})),
Action::ReasoningEffortUp | Action::ReasoningEffortDown => {
let settings = read_session_settings(session_id)?;
Comment on lines +207 to +210
fn read_session_settings(session_id: &str) -> Result<Value, String> {
let home = std::env::var_os("HOME").ok_or_else(|| "HOME is unavailable".to_string())?;
let root = PathBuf::from(home).join(".factory/sessions");
let direct = root.join(format!("{session_id}.settings.json"));
@DevVig
DevVig merged commit e085efe into main Jul 20, 2026
6 of 7 checks passed
@DevVig
DevVig deleted the feat/conductor-factory-effort branch July 20, 2026 19:55

@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: 6

Caution

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

⚠️ Outside diff range comments (1)
crates/microbridged/src/app_match.rs (1)

110-116: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make these assertions exercise the canonical mapping.

same_app returns immediately for identical strings, so these tests never call app_family or canonical_family. Compare the display labels with their stable keys instead.

Proposed test adjustment
-        assert!(same_app("Conductor", "Conductor"));
-        assert!(same_app("Factory", "Factory"));
+        assert!(same_app("Conductor", "conductor"));
+        assert!(same_app("Factory", "factory"));
🤖 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 `@crates/microbridged/src/app_match.rs` around lines 110 - 116, Update the test
function cursor_and_synara_match_themselves so assertions for identical
applications compare each display label with its stable key rather than the same
string, ensuring same_app invokes app_family and canonical_family. Preserve the
existing negative comparisons and canonical self-match assertions for Conductor
and Factory unless they likewise require display-label-to-key pairs.
🧹 Nitpick comments (1)
crates/mb-adapters/src/codex.rs (1)

192-193: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the explicit Conductor originator path.

The new ("conductor", "Conductor") mapping is not directly tested; the added Conductor case uses codex_sdk_ts and exercises host_from_cwd fallback instead. Add a conductor_desktop assertion alongside the Factory assertion.

Suggested assertion
         assert_eq!(codex_app_label(Some("synara_desktop"), None), "Synara");
         assert_eq!(codex_app_label(Some("t3code_desktop"), None), "T3 Code");
+        assert_eq!(codex_app_label(Some("conductor_desktop"), None), "Conductor");
         assert_eq!(codex_app_label(Some("factory_desktop"), None), "Factory");
🤖 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 `@crates/mb-adapters/src/codex.rs` around lines 192 - 193, Add a direct test
assertion for the ("conductor", "Conductor") mapping in the originator mapping
tests, using the conductor_desktop fixture or input alongside the existing
Factory assertion. Ensure the assertion exercises the explicit Conductor path
rather than the codex_sdk_ts host_from_cwd fallback.
🤖 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 `@apps/microbridge-ui/src-tauri/tauri.conf.json`:
- Line 75: Update the install flow in scripts/install.sh so
target/release/microbridgectl is copied or staged into
apps/microbridge-ui/src-tauri/binaries/ before npm run tauri build executes.
Ensure the staged filename matches the microbridgectl entry in the
tauri.conf.json externalBin configuration, while preserving the existing
microbridged staging behavior.

In `@crates/microbridged/src/factory.rs`:
- Around line 207-239: Validate session_id at the boundary of
read_session_settings before constructing any filesystem paths, rejecting empty
values and identifiers containing path separators, "..", or other path
components that could escape the sessions directory. Return a descriptive error
for invalid IDs, and only invoke find_settings or direct path construction after
validation.
- Around line 330-333: Update the assertion in
discovers_a_factory_droid_binary_outside_gui_path to avoid comparing binary with
an allocated PathBuf; compare against the borrowed "droid" path representation
instead, while preserving the existing is_file() alternative and test behavior.
- Around line 241-286: Replace the help-text parsing in parse_reasoning_levels
with the documented Microbridge contract for --reasoning-effort, using the
factory’s stable model/reasoning metadata rather than matching headings and
per-model line wording. Preserve the function’s Option<(Vec<String>, String)>
result and return the supported levels plus default for the requested model_id.

In `@crates/microbridged/src/t3code.rs`:
- Around line 91-94: Update the capabilities configuration containing focus_open
so it is true only on macOS by gating it with cfg!(target_os = "macos"). Keep
the existing focus behavior unchanged on macOS and ensure non-macOS targets no
longer advertise unsupported focus support.
- Around line 765-774: Extract the t3 thread deep-link construction from
open_thread into a reusable helper, preserving the existing Url path-segment
encoding behavior for environment and thread identifiers. Update open_thread and
constructs_the_official_t3_thread_deep_link to call this helper so the test
exercises production URL assembly.

---

Outside diff comments:
In `@crates/microbridged/src/app_match.rs`:
- Around line 110-116: Update the test function
cursor_and_synara_match_themselves so assertions for identical applications
compare each display label with its stable key rather than the same string,
ensuring same_app invokes app_family and canonical_family. Preserve the existing
negative comparisons and canonical self-match assertions for Conductor and
Factory unless they likewise require display-label-to-key pairs.

---

Nitpick comments:
In `@crates/mb-adapters/src/codex.rs`:
- Around line 192-193: Add a direct test assertion for the ("conductor",
"Conductor") mapping in the originator mapping tests, using the
conductor_desktop fixture or input alongside the existing Factory assertion.
Ensure the assertion exercises the explicit Conductor path rather than the
codex_sdk_ts host_from_cwd fallback.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b287932f-6988-48ab-b87d-86f69910d78b

📥 Commits

Reviewing files that changed from the base of the PR and between 3d6e20d and 81a3e00.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • apps/microbridge-ui/package-lock.json is excluded by !**/package-lock.json
  • apps/microbridge-ui/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (33)
  • .codex/environments/environment.toml
  • .github/workflows/release.yml
  • Cargo.toml
  • INSTALL.md
  • README.md
  • adapters/README.md
  • adapters/conductor/README.md
  • adapters/factory/README.md
  • adapters/synara/README.md
  • adapters/t3code/README.md
  • apps/microbridge-ui/package.json
  • apps/microbridge-ui/src-tauri/Cargo.toml
  • apps/microbridge-ui/src-tauri/src/lib.rs
  • apps/microbridge-ui/src-tauri/tauri.conf.json
  • apps/microbridge-ui/src/lib/bus.ts
  • apps/microbridge-ui/src/surfaces/Settings.tsx
  • apps/microbridge-ui/src/surfaces/surfaces.test.tsx
  • crates/mb-adapters/src/claude.rs
  • crates/mb-adapters/src/codex.rs
  • crates/mb-adapters/src/hosts.rs
  • crates/mb-protocol/src/lib.rs
  • crates/microbridgectl/src/main.rs
  • crates/microbridged/src/app_match.rs
  • crates/microbridged/src/factory.rs
  • crates/microbridged/src/lib.rs
  • crates/microbridged/src/main.rs
  • crates/microbridged/src/state.rs
  • crates/microbridged/src/t3code.rs
  • docs/adapters.md
  • docs/architecture.md
  • docs/protocol.md
  • docs/releases/v0.3.0.md
  • script/build_and_run.sh

"active": true,
"targets": "all",
"externalBin": ["binaries/microbridged"],
"externalBin": ["binaries/microbridged", "binaries/microbridgectl"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all tauri build invocations and check each is preceded by a microbridgectl copy.
rg -nP 'tauri\s+build|npm run tauri' -g '*.yml' -g '*.yaml' -g '*.sh' -C15
rg -n 'microbridgectl' -g '*.yml' -g '*.yaml' -g '*.sh'

Repository: DevVig/microbridge

Length of output: 156


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== candidate files ==\n'
git ls-files | rg '(\.github/workflows/.*\.ya?ml$|script/.*\.sh$|tauri\.conf\.json$|package\.json$|Cargo\.toml$)'

printf '\n== tauri build invocations ==\n'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' 'tauri(\s+build|[^[:alnum:]_:-])|npm run tauri|cargo tauri' .

printf '\n== microbridgectl references ==\n'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' 'microbridgectl' .

Repository: DevVig/microbridge

Length of output: 12994


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files under apps/microbridge-ui ==\n'
git ls-files 'apps/microbridge-ui/**'

printf '\n== package scripts ==\n'
sed -n '1,220p' apps/microbridge-ui/package.json

printf '\n== tauri config ==\n'
sed -n '1,180p' apps/microbridge-ui/src-tauri/tauri.conf.json

printf '\n== workflow files mentioning microbridge-ui ==\n'
rg -n --hidden --glob '.github/workflows/*.yml' --glob '.github/workflows/*.yaml' 'microbridge-ui|tauri|microbridgectl|build_and_run|externalBin' .github/workflows

printf '\n== shell scripts mentioning microbridge-ui ==\n'
rg -n --hidden --glob '*.sh' 'microbridge-ui|tauri|microbridgectl|externalBin' script .

Repository: DevVig/microbridge

Length of output: 14694


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,240p' apps/microbridge-ui/package.json

printf '\n== workflows ==\n'
for f in .github/workflows/*.{yml,yaml}; do
  [ -f "$f" ] || continue
  echo "--- $f ---"
  rg -n 'microbridge-ui|tauri|microbridgectl|externalBin|build_and_run|copy' "$f" || true
done

printf '\n== repo files containing microbridge-ui build references ==\n'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' 'microbridge-ui|tauri build|cargo tauri|build_and_run|externalBin|microbridgectl' .

Repository: DevVig/microbridge

Length of output: 18424


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== scripts/install.sh around the Tauri path ==\n'
sed -n '120,170p' scripts/install.sh

printf '\n== any microbridgectl staging near tauri build ==\n'
rg -n 'microbridgectl|tauri build|tauri dev|web build|copy' scripts/install.sh script/build_and_run.sh .github/workflows/release.yml

Repository: DevVig/microbridge

Length of output: 4345


Stage microbridgectl before npm run tauri build in scripts/install.sh.
scripts/install.sh:135-139 builds the UI bundle without copying target/release/microbridgectl into apps/microbridge-ui/src-tauri/binaries/, so this install path will trip over the new externalBin entry.

🤖 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 `@apps/microbridge-ui/src-tauri/tauri.conf.json` at line 75, Update the install
flow in scripts/install.sh so target/release/microbridgectl is copied or staged
into apps/microbridge-ui/src-tauri/binaries/ before npm run tauri build
executes. Ensure the staged filename matches the microbridgectl entry in the
tauri.conf.json externalBin configuration, while preserving the existing
microbridged staging behavior.

Comment on lines +207 to +239
fn read_session_settings(session_id: &str) -> Result<Value, String> {
let home = std::env::var_os("HOME").ok_or_else(|| "HOME is unavailable".to_string())?;
let root = PathBuf::from(home).join(".factory/sessions");
let direct = root.join(format!("{session_id}.settings.json"));
let path = if direct.is_file() {
direct
} else {
find_settings(&root, session_id, 3)
.ok_or_else(|| format!("Factory settings for session {session_id} were not found."))?
};
let content = std::fs::read_to_string(&path)
.map_err(|error| format!("read {}: {error}", path.display()))?;
serde_json::from_str(&content).map_err(|error| format!("parse {}: {error}", path.display()))
}

fn find_settings(root: &Path, session_id: &str, depth: usize) -> Option<PathBuf> {
if depth == 0 {
return None;
}
let wanted = format!("{session_id}.settings.json");
for entry in std::fs::read_dir(root).ok()?.flatten() {
let path = entry.path();
if path.file_name().and_then(|name| name.to_str()) == Some(wanted.as_str()) {
return Some(path);
}
if path.is_dir() {
if let Some(found) = find_settings(&path, session_id, depth - 1) {
return Some(found);
}
}
}
None
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Unsanitized session_id used to build a filesystem path.

read_session_settings/find_settings join session_id directly into a path under ~/.factory/sessions (root.join(format!("{session_id}.settings.json"))) with no check that it's free of //.. components. session_id originates from Factory's own hook payload today, but nothing here enforces that invariant at this boundary, so a malformed or unexpected session id could cause reads outside the intended directory.

🛡️ Proposed guard
 fn read_session_settings(session_id: &str) -> Result<Value, String> {
+    if session_id.is_empty() || session_id.contains(['/', '\\']) || session_id.contains("..") {
+        return Err(format!("invalid Factory session id: {session_id}"));
+    }
     let home = std::env::var_os("HOME").ok_or_else(|| "HOME is unavailable".to_string())?;
📝 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
fn read_session_settings(session_id: &str) -> Result<Value, String> {
let home = std::env::var_os("HOME").ok_or_else(|| "HOME is unavailable".to_string())?;
let root = PathBuf::from(home).join(".factory/sessions");
let direct = root.join(format!("{session_id}.settings.json"));
let path = if direct.is_file() {
direct
} else {
find_settings(&root, session_id, 3)
.ok_or_else(|| format!("Factory settings for session {session_id} were not found."))?
};
let content = std::fs::read_to_string(&path)
.map_err(|error| format!("read {}: {error}", path.display()))?;
serde_json::from_str(&content).map_err(|error| format!("parse {}: {error}", path.display()))
}
fn find_settings(root: &Path, session_id: &str, depth: usize) -> Option<PathBuf> {
if depth == 0 {
return None;
}
let wanted = format!("{session_id}.settings.json");
for entry in std::fs::read_dir(root).ok()?.flatten() {
let path = entry.path();
if path.file_name().and_then(|name| name.to_str()) == Some(wanted.as_str()) {
return Some(path);
}
if path.is_dir() {
if let Some(found) = find_settings(&path, session_id, depth - 1) {
return Some(found);
}
}
}
None
}
fn read_session_settings(session_id: &str) -> Result<Value, String> {
if session_id.is_empty() || session_id.contains(['/', '\\']) || session_id.contains("..") {
return Err(format!("invalid Factory session id: {session_id}"));
}
let home = std::env::var_os("HOME").ok_or_else(|| "HOME is unavailable".to_string())?;
let root = PathBuf::from(home).join(".factory/sessions");
let direct = root.join(format!("{session_id}.settings.json"));
let path = if direct.is_file() {
direct
} else {
find_settings(&root, session_id, 3)
.ok_or_else(|| format!("Factory settings for session {session_id} were not found."))?
};
let content = std::fs::read_to_string(&path)
.map_err(|error| format!("read {}: {error}", path.display()))?;
serde_json::from_str(&content).map_err(|error| format!("parse {}: {error}", path.display()))
}
fn find_settings(root: &Path, session_id: &str, depth: usize) -> Option<PathBuf> {
if depth == 0 {
return None;
}
let wanted = format!("{session_id}.settings.json");
for entry in std::fs::read_dir(root).ok()?.flatten() {
let path = entry.path();
if path.file_name().and_then(|name| name.to_str()) == Some(wanted.as_str()) {
return Some(path);
}
if path.is_dir() {
if let Some(found) = find_settings(&path, session_id, depth - 1) {
return Some(found);
}
}
}
None
}
🤖 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 `@crates/microbridged/src/factory.rs` around lines 207 - 239, Validate
session_id at the boundary of read_session_settings before constructing any
filesystem paths, rejecting empty values and identifiers containing path
separators, "..", or other path components that could escape the sessions
directory. Return a descriptive error for invalid IDs, and only invoke
find_settings or direct path construction after validation.

Comment on lines +241 to +286
fn parse_reasoning_levels(help: &str, model_id: &str) -> Option<(Vec<String>, String)> {
let mut in_models = false;
let mut display = None;
for line in help.lines() {
let trimmed = line.trim();
if trimmed == "Available Models:" {
in_models = true;
continue;
}
if trimmed == "Custom Models:" || trimmed == "Model details:" {
in_models = false;
}
if in_models {
let mut fields = trimmed.split_whitespace();
if fields.next() == Some(model_id) {
display = Some(
fields
.collect::<Vec<_>>()
.join(" ")
.trim_end_matches(" (default)")
.trim_end_matches(" [Deprecated]")
.to_string(),
);
break;
}
}
}
let display = display?;
let prefix = format!("- {display}: supports reasoning: Yes; supported: [");
let line = help
.lines()
.map(str::trim)
.find(|line| line.starts_with(&prefix))?;
let levels_raw = line.strip_prefix(&prefix)?.split(']').next()?;
let levels: Vec<String> = levels_raw
.split(',')
.map(|item| item.trim().to_string())
.collect();
let default = line
.split("default: ")
.nth(1)
.map(str::trim)
.unwrap_or_else(|| levels.first().map(String::as_str).unwrap_or("none"))
.to_string();
Some((levels, default))
}

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 | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Factory AI droid CLI exec --help stable output format reasoning effort JSON-RPC

💡 Result:

The Factory AI droid exec CLI is designed for headless, non-interactive automation and integration [1][2]. It supports configurable reasoning and structured output, making it suitable for CI/CD pipelines and programmatic agent interactions [2][3]. ### Reasoning Effort The reasoning effort level controls the model's deliberation depth [2]. You can configure this via the command-line flag -r or --reasoning-effort [4][5]. * Supported values: off, none, low, medium, high [2][6]. * Effect: off / none disables structured reasoning for maximum speed, while medium and high increase deliberation time for complex tasks [2][6]. * Usage example: droid exec "your task" --reasoning-effort high [4]. ### JSON-RPC and Output Formats For programmatic integration, droid exec supports several output formats, selectable via the -o or --output-format flag [3][5]. * stream-jsonrpc: Specifically designed for SDKs and persistent integrations, this format provides structured, machine-readable communication [7][5]. * stream-json: Useful for real-time monitoring of agent progress [2][5]. * json: Provides the final output only [2]. * text: Standard text output [5]. The Factory Droid SDK (e.g., droid-sdk-python) utilizes stream-jsonrpc over a subprocess, allowing you to manage session lifecycles, stream tool usage, and receive thinking process updates programmatically [7]. ### Summary of CLI Execution To view all available configuration options, use the built-in help command: droid exec --help [4][1] Key flags for automation include: * --auto <low|medium|high>: Sets the agent's autonomy level (default is read-only) [4][3]. * -m, --model <id>: Specifies the model ID to use for the execution [4][5]. * -o, --output-format <format>: Controls the data structure of the output [3][5]. * -s, --session-id <id>: Resumes an existing session [1][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant file and nearby references
git ls-files crates/microbridged/src/factory.rs
echo '--- outline ---'
ast-grep outline crates/microbridged/src/factory.rs --view expanded || true
echo '--- search for parse_reasoning_levels usage ---'
rg -n "parse_reasoning_levels|reasoning-effort|Available Models:|Model details:|supports reasoning" crates/microbridged/src/factory.rs crates/microbridged -S || true
echo '--- line count ---'
wc -l crates/microbridged/src/factory.rs

Repository: DevVig/microbridge

Length of output: 3261


🌐 Web query:

"Available Models:" "Model details:" "supports reasoning: Yes; supported:" Factory droid exec help

💡 Result:

Yes, Factory Droid supports reasoning across its command-line interface, including within droid exec [1][2][3]. The droid exec command supports reasoning through the --reasoning-effort flag (or -r shorthand) [1][2]. This flag allows users to control the depth of the AI's analysis, with available levels typically including off, low (default), medium, and high [2][3]. Increasing the effort level generally leads to deeper analysis at the cost of slower execution [3]. Key technical details regarding reasoning support include: - Flag Usage: You can specify reasoning effort directly in your command, for example: droid exec -r high "your prompt here" [2]. - Automation Contexts: The reasoning effort can also be configured in automated environments, such as within GitHub Actions (via the reasoning_effort input) [4] or when building interactive apps via droid exec [3]. - Limitations: While core support is widespread, it is noted in some documentation that reasoning effort may not yet be supported for certain custom models, though this is subject to change [1]. - Interaction: In the interactive TUI mode of the Droid CLI, you can cycle through reasoning effort levels by pressing Tab [2]. For further assistance, you can use the droid exec --help command directly in your terminal to see the most up-to-date configuration options for your specific version of the Droid CLI [1][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '40,75p' crates/microbridged/src/factory.rs
echo '--- tests ---'
sed -n '299,334p' crates/microbridged/src/factory.rs

Repository: DevVig/microbridge

Length of output: 3045


Parse a documented contract instead of --help text Factory’s docs expose --reasoning-effort, but this parser depends on the exact Available Models: / Model details: layout and per-model line wording. Any CLI text change will disable reasoning-effort adjustment for Microbridge users and surface as a user-facing error.

🤖 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 `@crates/microbridged/src/factory.rs` around lines 241 - 286, Replace the
help-text parsing in parse_reasoning_levels with the documented Microbridge
contract for --reasoning-effort, using the factory’s stable model/reasoning
metadata rather than matching headings and per-model line wording. Preserve the
function’s Option<(Vec<String>, String)> result and return the supported levels
plus default for the requested model_id.

Comment thread crates/microbridged/src/factory.rs
Comment on lines 91 to +94
new_session: false,
focus_open: false,
// T3 publishes a stable, semantic deep link for a specific environment
// and thread. This deliberately avoids synthesizing UI keybindings.
focus_open: true,

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 | 🟠 Major | ⚡ Quick win

Gate focus_open by platform.

capabilities() advertises focus support on every target, but open_thread explicitly fails on non-macOS. This lets AdapterCapabilities::supports expose an action that cannot succeed. Use cfg!(target_os = "macos") for focus_open or restrict this adapter capability to macOS builds.

Also applies to: 610-613

🤖 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 `@crates/microbridged/src/t3code.rs` around lines 91 - 94, Update the
capabilities configuration containing focus_open so it is true only on macOS by
gating it with cfg!(target_os = "macos"). Keep the existing focus behavior
unchanged on macOS and ensure non-macOS targets no longer advertise unsupported
focus support.

Comment on lines +765 to +774

#[test]
fn constructs_the_official_t3_thread_deep_link() {
let mut url = Url::parse("t3code://threads/").unwrap();
url.path_segments_mut()
.unwrap()
.push("environment 1")
.push("thread/1");
assert_eq!(url.as_str(), "t3code://threads/environment%201/thread%2F1");
}

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:

ast-grep outline crates/microbridged/src/t3code.rs --view expanded
sed -n '700,820p' crates/microbridged/src/t3code.rs
rg -n "open_thread|path_segments_mut|thread%2F1|constructs_the_official_t3_thread_deep_link|environment 1" crates/microbridged/src/t3code.rs

Repository: DevVig/microbridge

Length of output: 5474


🏁 Script executed:

sed -n '586,610p' crates/microbridged/src/t3code.rs

Repository: DevVig/microbridge

Length of output: 1133


Extract the deep-link builder. This test only checks Url segment encoding; it won’t catch regressions in open_thread while the production URL assembly stays inline. Move that construction into a helper shared by open_thread and the 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 `@crates/microbridged/src/t3code.rs` around lines 765 - 774, Extract the t3
thread deep-link construction from open_thread into a reusable helper,
preserving the existing Url path-segment encoding behavior for environment and
thread identifiers. Update open_thread and
constructs_the_official_t3_thread_deep_link to call this helper so the test
exercises production URL assembly.

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.

2 participants