feat: add native interoperability and extension workflows - #887
feat: add native interoperability and extension workflows#887haasonsaas wants to merge 24 commits into
Conversation
|
This PR changes mirrored Maestro source files in the public repo, but it does not link the matching private source-of-truth PR. Add one of these to the PR body, then re-run the check:
Mirrored files touched:
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5b202f2e7a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9fcabce631
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6bfe334acc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 296288c665
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 409620ffd6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 341e47a4e0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8ae0e8867
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1b6fe91544
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f4d6997a3e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| remainder | ||
| .strip_prefix(':') | ||
| .is_some_and(looks_like_colon_credential_value) |
There was a problem hiding this comment.
Redact quoted JSON credential assignments
Fresh evidence after the assignment/header fixes is that common JSON output such as {"access_token":"secret"} remains unchanged: after matching access_token, the remainder begins with a quote rather than = or :, so this predicate returns false. Hosted tool, command, and file-read output containing OAuth JSON is therefore persisted and streamed with the credential intact; recognize quoted JSON keys before publishing the message.
AGENTS.md reference: AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
| "secret", | ||
| "password", | ||
| "privatekey", | ||
| ] |
There was a problem hiding this comment.
Redact structured credential fields
When a tool call contains a field such as provider_credentials or credentials, normalization produces providercredentials/credentials, but none of these markers match it. SharedRunner::publish_message consequently retains and broadcasts that plaintext field even though the hosted retention contract explicitly treats provider_credentials as forbidden plaintext; include credential-named fields in the structured redaction classifier.
AGENTS.md reference: AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 07854b889e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "token" | ||
| | "apikey" | ||
| | "secret" | ||
| | "clientsecret" | ||
| | "accesstoken" |
There was a problem hiding this comment.
Reject auth-token credentials in plugin URLs
When a remote source uses a credential parameter such as ?auth_token=secret, normalization produces authtoken, which is absent from this allowlist. The URL is therefore passed to git clone, persisted verbatim as trusted_source, and echoed in the successful install preview, defeating the stated credential rejection boundary; use the comprehensive secret-key classifier here as well.
Useful? React with 👍 / 👎.
| // The aggregate becomes durable only at response | ||
| // completion. Giving it the completion cursor keeps | ||
| // replay cursors monotonic and resumable. | ||
| cursor, |
There was a problem hiding this comment.
Give coalesced chunks and completions distinct resume positions
When a coarse subscriber disconnects after receiving the synthesized aggregate but before the immediately following ResponseEnd, both events carry this same completion cursor. The client has already advanced its resume cursor after the chunk, so replay suppresses both cursor-equal events and the response never receives its terminal lifecycle event. Fresh evidence after the earlier replay fix is this two-envelope, one-cursor delivery boundary; make the pair atomically resumable or assign distinct resume positions.
AGENTS.md reference: AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 80aeb90e06
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let mut plugin_config = match plugin_path.extension().and_then(|value| value.to_str()) { | ||
| Some("json") => load_json_config_file(plugin_path)?, | ||
| _ => load_config_file(plugin_path)?, |
There was a problem hiding this comment.
Isolate malformed plugin hook configurations
When any enabled plugin contains malformed hooks.json or hooks.toml, the propagated parse error aborts the entire combined load after valid global and project hooks have already been merged. IntegratedHookSystem::load_from_config then discards that result, so one broken plugin disables every configured hook rather than only that plugin; validate plugin hook files during installation or warn and continue past individual plugin parse failures.
Useful? React with 👍 / 👎.
| match args[index].as_str() { | ||
| "--scope" => { |
There was a problem hiding this comment.
Preserve MCP subprocess options after a delimiter
For a stdio server whose own CLI needs an argument named --scope or --env, this parser always consumes that argument as Maestro configuration—even when the caller places it after --. The child therefore receives altered argv, and a child --scope project can additionally change where the server is persisted; recognize a positional delimiter and forward all following arguments verbatim.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1ca4dec65
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| FromAgentMessage::ResponseEnd { response_id, .. } | ||
| if !active_responses.remove(response_id.as_str()) => | ||
| { | ||
| return false; |
There was a problem hiding this comment.
Accept unmatched terminal response markers during replay
Fresh evidence after the earlier response-boundary fixes is that NativeAgentRunner emits the UUID-scoped completion from run_loop and then a second ResponseEnd { response_id: "done" } at agent/native.rs:1719-1722 after every ordinary prompt. This branch treats that normal lifecycle marker as an incomplete boundary, so any turn/block subscriber established while it remains in the retained window receives coarse_replay_incomplete instead of the retained transcript; allow lifecycle-only terminal markers while continuing to reject genuinely orphaned response events.
AGENTS.md reference: AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
| } else if contains_credential_marker(content) { | ||
| *content = "[REDACTED]".to_string(); |
There was a problem hiding this comment.
Scan credential markers in JSON scalar outputs
Fresh evidence after the structured-JSON fix is that valid JSON scalar or scalar-array output, such as content exactly "access_token=secret" or ["access_token=secret"], parses successfully but is unchanged by the structured redact walk. Because marker scanning only occurs in this parse-failure branch, SharedRunner::publish_message journals and broadcasts the plaintext credential; scan string values within parsed JSON or fall back to marker scanning whenever structured redaction makes no changes.
AGENTS.md reference: AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
| return ( | ||
| vec![self.reset_envelope_from_state(&state, "coarse_replay_incomplete")], | ||
| rx, |
There was a problem hiding this comment.
Make equal-cursor coarse replay resets visible
Fresh evidence after the server-side replay reset fixes is the equal-cursor native-client path: remote connections start their event reader at the subscription snapshot cursor, and when an incomplete coarse replay is detected at that same current cursor, this reset carries an equal snapshot cursor. headless/remote_transport.rs:1386-1389 rejects resets unless their cursor strictly advances, so the authoritative recovery event is silently discarded; either make reset envelopes independently advance or allow equal-cursor resets in the remote reader.
AGENTS.md reference: AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9993e9a735
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let Some(index) = lower.find("authorization:") else { | ||
| return false; |
There was a problem hiding this comment.
Reject quoted JSON authorization arguments
When add-stdio receives a child argument such as --headers '{"Authorization":"Bearer literal-secret"}', this exact substring check misses it because the quoted key contains authorization":" rather than authorization:. Neither argument is then classified as credential-bearing, so the literal is persisted, and the same helper also leaves it visible in mcp list; parse JSON-shaped arguments or recognize quoted authorization keys before accepting them.
AGENTS.md reference: AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
| let mut meta = meta | ||
| .lock() | ||
| .unwrap_or_else(std::sync::PoisonError::into_inner); | ||
| meta.response_chunks.push((content.clone(), is_thinking)); |
There was a problem hiding this comment.
Avoid buffering delta transcript chunks
For the default Delta transcript grade, every response chunk is already emitted immediately, but this line also clones and retains the complete response until ResponseEnd. A long generation therefore changes the streaming path from constant-memory processing to O(response-size) extra memory and can exhaust the headless server even though the accumulated content is never used for this grade; only buffer chunks for Turn or Block subscribers.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8d441a9fc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let plugin_paths = crate::plugins::PluginRegistry::discover_for_workspace(cwd).hook_configs(); | ||
| load_hook_config_with_plugin_paths(cwd, &plugin_paths) |
There was a problem hiding this comment.
Require workspace trust before loading project plugin hooks
In an untrusted checkout containing .maestro/plugins/<name>/hooks.toml, this discovery path loads the repository-controlled plugin automatically without consulting workspace_trusted_in_global_config; a missing plugin-state.json also defaults every capability to enabled. As a result, Lua/WASM hooks from a newly opened repository can become active despite the comment below claiming workspace and installation trust were already enforced; gate project-origin plugin discovery or hook loading on the global workspace trust decision.
Useful? React with 👍 / 👎.
| [ | ||
| "authorization", | ||
| "apikey", | ||
| "accesstoken", | ||
| "refreshtoken", | ||
| "token", | ||
| "password", | ||
| "secret", | ||
| "privatekey", | ||
| ] |
There was a problem hiding this comment.
Classify credential-named MCP arguments
Fresh evidence after the OAuth flag fixes is that maestro mcp add-stdio svc cmd --credentials opaque-secret still passes validation because credentials matches none of these markers. The literal is persisted in args, and the same classifier used by mcp list leaves both the flag and value unredacted, so common credential-bearing arguments can still be printed in plaintext; include credential variants in the shared classifier.
Useful? React with 👍 / 👎.
Summary
Maestro can now expose the extension and interoperability workflows selected from Kimi Code without falling back to a second runtime: external ACP clients, installable plugins, conversational MCP setup, model-resolution provenance, graded transcript subscriptions, syntax-aware Bash safety, and bounded video input all run natively in Rust.
ffmpegprocess.The security boundary stays explicit: plugin trust state fails closed, manifest paths and copied content cannot escape through symlinks, interrupted installs remain inactive, MCP credentials must use environment references, private configuration writes are atomic, and model/transcript output redacts credentials. ACP cancellation terminates the underlying runner, and video decoding is bounded by frame count and timeout.
Related: evalops/maestro-internal#3187
Validation
npm run checkpassed, including the Rust-only source/document guards and locked workspace checks.npm run release:checkpassed; the optimized native package ran successfully with Node, npm, Bun, and npx removed from the childPATH.cargo fmt --all -- --checkandgit diff --checkpassed.sandbox.rsandapp.rs.cargo test --workspace --lockedreached 3,898 passing tests before four local failures: two existing macOS/varversus/private/varcanonicalization assertions and two MCP timeout cases under full parallel load. Both MCP cases passed immediately when rerun alone.New concepts
ACP as a protocol boundary
The Agent Client Protocol is a versioned JSON-RPC boundary between an editor/client and an agent runtime. Here, the adapter translates ACP lifecycle methods into Maestro's existing headless request path, so protocol support does not create a second execution engine.
This is preferable to a Maestro-specific editor integration because clients can negotiate capabilities and reuse the same session primitives. The implementation handles
initialize,session/new,session/prompt, and cancellation while advertising only behavior Maestro actually supports.Use a direct in-process API instead when both caller and runtime are owned together and protocol interoperability is unnecessary.
Syntax trees for shell policy
A tree-sitter parse identifies shell constructs by syntax rather than by substrings alone. That lets the safety layer distinguish commands, substitutions, redirections, and compound expressions while retaining a conservative fallback when parsing is incomplete.
This is useful here because quoting and nesting make textual shell matching fragile, but the existing approval policy still owns the final decision. The parser improves evidence; it does not silently broaden permissions.
Avoid the parser cost for already-tokenized command arrays or inputs whose grammar is deliberately restricted to a simpler form.
Post-Deploy Monitoring & Validation
ffmpegprocesses.