Two execution contexts are easy to confuse: OpenCode's project tools run in the project's execution environment, while an SSH session only proves that you can reach a remote host. The OpenCode tools documentation describes where its bash tool runs. To build with Xcode, put the active workspace and command execution on the remote Mac, or explicitly dispatch commands there—and verify file changes, xcodebuild, and saved test results separately.

Who should read this: You develop on Windows or Linux but need to build an iOS or macOS project.
You maintain a remote Mac CI node and need to distinguish the agent workspace from the build host.
You are connecting OpenCode to Apple toolchains and need a clear permission and acceptance boundary.

Last updated October 24, 2026. OpenCode behavior was checked against its official tools documentation and change log; Apple toolchain and test details were checked against the official Xcode documentation linked below.

01

Start with the host that actually runs the command

When a command reports success but the remote Mac has no corresponding build output, do not begin by reinstalling Xcode. First establish where the command ran.

SSH connectivity and agent execution are separate checks. You might be able to open an SSH session from your workstation while OpenCode continues to run its terminal tool in a local project environment. In that case, xcodebuild runs locally unless you deliberately route it to the Mac. A working SSH connection does not automatically forward OpenCode's file operations or shell commands.

Use a host check from the exact command environment OpenCode uses. For macOS or Linux shells, hostname and pwd can identify the host and current directory. If the command runs on Windows, use the platform's host and path commands instead. Then compare that result with a separately opened SSH session on the Mac. Do not infer the execution host from the terminal window you happen to be viewing.

A practical case: you launch OpenCode from a Linux checkout, then open SSH to a Mac in another terminal. OpenCode edits the Linux checkout and reports that a shell command completed. The Mac is reachable, but it has not built those edits. The likely fault is the execution boundary, not an Xcode compile error.

The OpenCode tool documentation is the source of truth for the bash tool's project execution context. Also check the official change log before diagnosing behavior from a version label alone: OpenCode 2.x continues to receive releases, so “2.0” by itself does not identify every current behavior or configuration detail.

02

Choose an execution model before changing files

Pick one of these models and make the boundary explicit. The right choice depends on whether you want the agent itself to read and edit the Mac workspace, or only want the Mac to perform builds.

Execution model Where OpenCode reads and edits files Where Xcode commands run Choose it when
Local agent, local workspace Windows or Linux checkout Local host unless separately dispatched You only need local analysis or edits and do not need the Apple toolchain in the agent's environment
Agent in a remote Mac workspace Remote Mac checkout Remote Mac You want the agent's file operations and Xcode commands to use the same project copy
Local agent with explicit SSH dispatch Usually the local checkout; remote files need a deliberate transfer or shared workspace Remote Mac through an SSH command You already have orchestration around remote commands and can prove which files the Mac receives

The first model is not a remote Mac development environment just because SSH is available. The second makes host and workspace alignment easier to inspect, but requires you to arrange agent access to the Mac workspace. The third can fit an existing macOS CI pipeline, but introduces a handoff: the remote build must receive the intended source revision and return its outputs.

Do not let the project silently drift between these models. Record where OpenCode starts, what path it treats as the repository root, and how a build command reaches the Mac. If those facts are unclear, you cannot reliably determine which copy was changed or built.

03

Match the agent workspace to the repository copy

A frequent failure is not a missing tool. It is the right tool operating on the wrong checkout.

Check the repository root from OpenCode's own command tool. Then check the root in the Mac's SSH session. Compare the repository identity, branch, commit, and working-tree changes. If you use separate local and remote clones, compare the commit identifiers before building. Do not rely on directory names; two different checkouts can both be called project.

For a controlled check, select a harmless file that the agent is expected to edit. Inspect its change in the workspace OpenCode reports. Then inspect the corresponding file on the Mac. If the change is absent remotely, your file operation did not reach that checkout. If it appears in both places, confirm that both copies are at the intended commit and that no sync step overwrote the edit.

For a remote build, record the revision used by the Mac job in its logs. A build result without a traceable source revision is weak evidence: you may be looking at a successful build of an older checkout. In a macOS CI flow, pass a known revision or create a clean working tree before the build, then retain the revision alongside the build and test artifacts.

This check also helps answer whether OpenCode is using the remote project directory. The answer is yes only when the agent's file operations target that directory, or when you have an explicit, verified synchronization mechanism. An SSH command that happens to use a remote working directory does not make the agent's local edits remote.

04

Verify xcodebuild in the remote execution account

If the agent is already executing commands on the Mac, inspect toolchain discovery from that same account and shell. A command that works in your interactive desktop session may not resolve for an automation account with a different environment.

Check the resolved path for xcodebuild, then inspect the active developer directory. Compare both with the Xcode installation your project expects. Apple's command-line tools installation documentation explains the installation boundary, while the Xcode command-line tool reference documents the command-line tools, including xcodebuild.

Use the same account that OpenCode or the CI job uses. If the command is absent, determine whether the required tools are installed on the Mac before changing shell startup files. If the command resolves to an unexpected installation, confirm the active developer directory and select the intended toolchain according to your team's setup. Then rerun the lookup through OpenCode's actual execution path.

Keep local and remote evidence separate. A local xcodebuild -version result establishes the local toolchain state; it says nothing about the Mac. Likewise, a successful SSH login establishes reachability, not the remote account's developer directory or command search path.

05

Separate repository access, credentials, and agent permissions

A project can be visible while its build still fails because different operations require different access. Treat repository read/write access, private dependency credentials, code-signing material, and OpenCode's file or tool permissions as separate checks.

Start with the exact error. A repository fetch failure points toward repository access or credentials. A dependency-resolution error may indicate that the remote account cannot access a private package source. A signing failure concerns signing configuration or its credentials; it does not prove that the agent lacks permission to edit source files. A denied tool call may instead be an OpenCode permission decision.

OpenCode documents configurable tool permissions. Review the policy that applies to the actual project and command. Grant only the access required for the failing operation, and avoid broad permissions as a diagnostic shortcut. In particular, do not copy signing secrets into a general workspace just to see whether a build proceeds. Keep credentials under the control of the account or CI secret mechanism responsible for using them.

After changing access, repeat only the operation that failed and retain its output. If a dependency fetch now succeeds but signing still fails, you have separated the faults rather than treating the whole build as one permission problem.

06

Distinguish a successful build from an available test destination

A build can succeed while a Simulator test cannot start. Check the scheme, destination, and required Simulator runtime against the task you intend to run. A missing or mismatched destination is not proof that OpenCode failed to execute the command.

First inspect which schemes and destinations the remote Xcode installation exposes. Compare that inventory with the scheme and destination named in your build or test invocation. Then verify that the remote Mac has the Simulator runtime required by the test target. Apple's guide to running an app on simulated or physical devices describes the device and destination side of the workflow.

Keep the outcomes distinct in logs:

  • Build passed: the requested build action completed.
  • Tests started: the test action began against a usable destination.
  • Tests passed or failed: the test runner reported an outcome.
  • Results retained: the result bundle was saved and collected.

Do not treat the first statement as evidence for the other three. If a scheme builds but its test destination is unavailable, correct the destination or runtime selection before changing agent permissions or reinstalling unrelated tools.

07

Capture a result you can inspect and reproduce

A completed command is not enough if its outcome cannot be reviewed later. For a test run, capture the process exit status, specify a result-bundle path, and make sure the CI artifact step collects that path from the Mac that ran the test. Apple documents test execution and result interpretation in Running tests and interpreting results.

Use explicit placeholders in your pipeline rather than an implicit default location:

xcodebuild test \
  -workspace <workspace-path> \
  -scheme <scheme-name> \
  -destination '<destination-specifier>' \
  -resultBundlePath <remote-result-bundle-path>

The values in angle brackets are placeholders, not literal settings. Choose a destination that exists on the remote host and a result path the job can write. Preserve the command output and exit status. After the run, verify that the result bundle exists on the Mac and that the artifact-collection step retrieved it. Open the saved bundle to review the test details; do not infer a test result from a build log alone.

For a useful rerun, use the same source revision and the same scheme and destination. If the rerun differs, note the changed environment or inputs before calling the issue fixed. That gives you a defensible basis to close the incident, continue investigating, or change the execution model.

08

FAQ: OpenCode and remote Xcode failures

Is OpenCode's bash command running locally or on the remote Mac?
Check the host from the command tool OpenCode actually invoked, then compare it with the host in your SSH session. If those differ, the agent's command is not running on the Mac merely because SSH works. Decide whether to move the agent workspace to the Mac or explicitly dispatch the build command to the remote host.

How do I point OpenCode at a project directory on a remote Mac?
Make the Mac checkout the actual workspace available to OpenCode, then verify the repository root and commit from the agent's command environment. If OpenCode remains local, use a defined synchronization or dispatch step and verify that the remote build uses the same revision. Do not assume a matching folder name means the same project copy.

SSH works, but the agent cannot find xcodebuild. What now?
Run command lookup and inspect the active developer directory from the same remote account that runs the agent or CI job. Confirm the required Xcode tools are installed on that Mac. A local lookup, an interactive login, or a successful SSH connection cannot establish the automation account's toolchain state.

How can I confirm test results were saved after xcodebuild succeeds?
Set a result-bundle path, retain the test command's exit status, and check that the bundle exists on the remote host. Then confirm your artifact collection step transfers that exact path and open the bundle to inspect the outcome. A successful build does not establish that tests ran or that their results were retained.

09

Run an acceptance check before returning the job to CI

Use the same execution route that failed. Do not validate through an interactive terminal and then assume the automated agent inherits that environment.

  • Confirm the host and working directory from OpenCode's actual command tool.
  • Confirm the repository root, source revision, and expected file changes on the build host.
  • Resolve xcodebuild and check the active developer directory as the execution account.
  • Run the intended scheme against an available destination.
  • Capture the command outcome and verify the result bundle and artifact handoff.
  • Repeat against the same revision if you need to confirm a repair.

If the first check fails, fix the specific boundary it exposes. A workspace mismatch calls for a workspace or synchronization change. An unavailable toolchain calls for a remote installation or selection fix. A denied operation calls for a narrow permission adjustment. A missing result bundle calls for a test-output or artifact-collection fix.

10

Choose the next step based on the failed boundary

If OpenCode runs locally, the Mac checkout is separate, and you have no verified transfer or remote dispatch step, do not treat the Mac as the build host yet. Move the active workspace to an accessible Mac environment or deliberately route the build and its artifacts through SSH. If the agent is already on the Mac, repair the account-specific toolchain, destination, or permissions and rerun the acceptance checks.

A local Windows or Linux workstation remains a good fit when you only need editing, analysis, or tools available on that host. It cannot supply Apple's Xcode toolchain by itself. A self-managed Mac can work well when you need a persistent node and can handle its upkeep, account security, and CI operations. For a temporary test environment or a project that needs Mac access without buying and maintaining another machine, you can review VpsMesh Mac options and compare the available arrangement with your actual workspace, access, and toolchain requirements. Check VpsMesh pricing information before deciding; do not assume a remote Mac alone fixes a workspace or permissions problem.

The useful dividing line is evidence: if your current setup cannot show which host changed the files, ran xcodebuild, and saved the test results, fix that execution path before scaling the CI job. If the blocker is simply that your workstation lacks an Apple toolchain, a remotely accessible Mac is an option to evaluate—not a substitute for verifying the build workflow.