Skip to content

feat(acp): add machine stdio transport for Acepe#2858

Open
flazouh wants to merge 2 commits intoantinomyhq:mainfrom
flazouh:feat/machine-stdio-acp
Open

feat(acp): add machine stdio transport for Acepe#2858
flazouh wants to merge 2 commits intoantinomyhq:mainfrom
flazouh:feat/machine-stdio-acp

Conversation

@flazouh
Copy link
Copy Markdown

@flazouh flazouh commented Apr 5, 2026

Abstract

This PR adds a real forge machine stdio entrypoint backed by Forge's ACP stdio transport. It is primarily for our app, Acepe, which needs to launch Forge from a stable CLI surface without depending on an unpublished feature branch.

Product Context

Acepe is our desktop app for running and managing coding agents across providers and protocols.

Product links:

Problem

Acepe integrates Forge as an installable local provider. That integration needed a released Forge command that can:

  • start a machine-oriented stdio session from the public CLI
  • speak ACP over stdio instead of only parsing a placeholder command
  • be launched by Acepe as a normal installed binary

Before this change, the relevant command path was missing on main. We could add parser coverage for forge machine stdio, but that would still leave the command non-functional at runtime, which does not unblock Acepe.

Solution

This change wires the machine-facing CLI entrypoint all the way through to a working ACP stdio server:

  • adds machine stdio as a first-class top-level CLI command
  • routes the CLI command through forge_main into a dedicated stdio runner
  • extends the public API surface with acp_start_stdio() so the transport can be started through the current app/service stack
  • ports the ACP stdio transport implementation into forge_app
  • adds the required ACP dependency wiring in the workspace and app manifests
  • preserves parser-level coverage and adds transport-adjacent verification

The intent is to keep the public invocation simple while making the underlying server path real and launchable by external applications.

ASCII Schemas

Before

+---------+              +------------------------+
| Acepe   | -- spawn --> | forge machine stdio    |
| app     |              | on forge main          |
+---------+              +-----------+------------+
                                    |
                                    v
                         +------------------------+
                         | missing / non-working  |
                         | machine transport      |
                         +------------------------+
                                    |
                                    v
                             integration blocked

After

+---------+              +------------------------+
| Acepe   | -- spawn --> | forge machine stdio    |
| app     |              | stable CLI entrypoint  |
+---------+              +-----------+------------+
                                    |
                                    v
                         +------------------------+
                         | forge_main acp_runner  |
                         +-----------+------------+
                                    |
                                    v
                         +------------------------+
                         | forge_api::            |
                         | acp_start_stdio()      |
                         +-----------+------------+
                                    |
                                    v
                         +------------------------+
                         | forge_app ACP stdio    |
                         | transport + adapter    |
                         +-----------+------------+
                                    |
                                    v
                         +------------------------+
                         | Acepe <-> Forge over   |
                         | ACP / stdio            |
                         +------------------------+

Ownership Boundary

Acepe responsibilities
----------------------
- install Forge
- discover provider
- spawn `forge machine stdio`
- speak ACP over stdio

Forge responsibilities
----------------------
- expose stable machine CLI
- initialize ACP transport
- adapt ACP requests into Forge services
- stream ACP responses back over stdio

Why This Is For Acepe

Acepe needs Forge to expose a stable, installable machine transport from main so our desktop app can launch Forge directly as a provider. This PR moves that capability into the open-source Forge repo so Acepe no longer has to depend on branch-specific or unpublished transport work.

Files Of Interest

  • crates/forge_main/src/cli.rs
  • crates/forge_main/src/ui.rs
  • crates/forge_main/src/acp_runner.rs
  • crates/forge_api/src/api.rs
  • crates/forge_api/src/forge_api.rs
  • crates/forge_app/src/acp_app.rs
  • crates/forge_app/src/acp/

Verification

I verified the change with:

env PROTOC=/tmp/protoc-28.3/bin/protoc cargo test --manifest-path /Users/alex/Documents/forgecode/Cargo.toml -p forge_main machine_stdio
env PROTOC=/tmp/protoc-28.3/bin/protoc cargo test --manifest-path /Users/alex/Documents/forgecode/Cargo.toml -p forge_app acp
env PROTOC=/tmp/protoc-28.3/bin/protoc cargo test --manifest-path /Users/alex/Documents/forgecode/Cargo.toml -p forge_app acp::conversion

Notes

  • protoc was not available on PATH in the local environment, so verification used a staged temporary binary.
  • The PR is intentionally focused on exposing the stdio ACP transport through the current CLI/API layers rather than reworking unrelated provider or UI behavior.

Expose a machine stdio entrypoint in Forge and route it through a real ACP stdio transport so Acepe can launch Forge as an installable provider instead of depending on an unpublished branch.

Co-Authored-By: ForgeCode <noreply@forgecode.dev>
@github-actions github-actions bot added the type: feature Brand new functionality, features, pages, workflows, endpoints, etc. label Apr 5, 2026
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 5, 2026

CLA assistant check
All committers have signed the CLA.

Comment on lines +39 to +42
fn acp_start_stdio(&self) -> impl std::future::Future<Output = Result<()>> + Send {
self.called.store(true, Ordering::SeqCst);
async { Ok(()) }
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The test implementation has incorrect async behavior. The self.called.store() executes immediately when the future is created, not when it's awaited. This means the test doesn't accurately verify that the async function is actually executed.

fn acp_start_stdio(&self) -> impl std::future::Future<Output = Result<()>> + Send {
    let called = self.called.clone();
    async move {
        called.store(true, Ordering::SeqCst);
        Ok(())
    }
}
Suggested change
fn acp_start_stdio(&self) -> impl std::future::Future<Output = Result<()>> + Send {
self.called.store(true, Ordering::SeqCst);
async { Ok(()) }
}
fn acp_start_stdio(&self) -> impl std::future::Future<Output = Result<()>> + Send {
let called = self.called.clone();
async move {
called.store(true, Ordering::SeqCst);
Ok(())
}
}

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

- Replace unbounded notification channel with bounded (1024) to apply
  backpressure when the client stalls
- Add per-session model override to prevent concurrent sessions from
  interfering with each other
- Replace From<Error> impl with explicit into_acp_error() per project
  guidelines
- Extract classify_mcp_tool() and convert to free functions, removing
  the unnecessary ToolOutputConverter struct
- Validate MCP server names (length, charset) to prevent injection
- Add MAX_BLOB_SIZE (50 MB) guard on base64-decoded resources
- Add I/O timeout (5 min) and graceful shutdown drain (5 s) to prevent
  indefinite hangs
- Track cancellation via AtomicBool across loop iterations
- Log warnings instead of silently ignoring reload/config errors
- Add tests for tool kind mapping, file extraction, and edge cases

Co-Authored-By: ForgeCode <noreply@forgecode.dev>
@flazouh flazouh force-pushed the feat/machine-stdio-acp branch from a2e5e58 to 8fe513f Compare April 5, 2026 22:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature Brand new functionality, features, pages, workflows, endpoints, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants