Skip to content

Commit 797740f

Browse files
patnikoCopilot
andcommitted
feat: add remote session support across all SDKs
Add a `remote` option to CopilotClientOptions in all 4 language SDKs (Node, Python, Go, .NET) that passes `--remote` to the CLI process, enabling Mission Control integration for GitHub web and mobile access. Also adds `session.rpc.remote.enable()` and `session.rpc.remote.disable()` RPC methods for on-demand per-session toggling, providing parity with the CLI's `/remote on` and `/remote off` commands. Changes: - Node: remote option in CopilotClientOptions, generated RPC types - Python: remote field on SubprocessConfig, manual RPC types - Go: Remote field on ClientOptions, manual RPC types - .NET: Remote property on CopilotClientOptions + clone, generated RPC - Docs: new docs/features/remote-sessions.md with all-language examples - Updated docs/features/index.md and docs/index.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9678a79 commit 797740f

14 files changed

Lines changed: 408 additions & 0 deletions

File tree

docs/features/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ These guides cover the capabilities you can add to your Copilot SDK application.
1717
| [Streaming Events](./streaming-events.md) | Subscribe to real-time session events (40+ event types) |
1818
| [Steering & Queueing](./steering-and-queueing.md) | Control message delivery — immediate steering vs. sequential queueing |
1919
| [Session Persistence](./session-persistence.md) | Resume sessions across restarts, manage session storage |
20+
| [Remote Sessions](./remote-sessions.md) | Share sessions to GitHub web and mobile via Mission Control |
2021

2122
## Related
2223

docs/features/remote-sessions.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Remote Sessions
2+
3+
Remote sessions let users access their Copilot session from GitHub web and mobile via [Mission Control](https://github.com). When enabled, the SDK connects each session to Mission Control, producing a URL that can be shared as a link or QR code.
4+
5+
## Prerequisites
6+
7+
- The user must be authenticated (GitHub token or logged-in user)
8+
- The session's working directory must be a GitHub repository
9+
10+
## Enabling Remote Sessions
11+
12+
### Always-on (client-level)
13+
14+
Set `remote: true` when creating the client. Every session in a GitHub repo automatically gets a remote URL.
15+
16+
<!-- tabs:start -->
17+
18+
#### **TypeScript**
19+
20+
```typescript
21+
import { CopilotClient } from "@github/copilot-sdk";
22+
23+
const client = new CopilotClient({ remote: true });
24+
const session = await client.createSession({
25+
workingDirectory: "/path/to/github-repo",
26+
onPermissionRequest: async () => ({ allowed: true }),
27+
});
28+
29+
session.on("session.info", (event) => {
30+
if (event.data.infoType === "remote") {
31+
console.log("Remote URL:", event.data.url);
32+
}
33+
});
34+
```
35+
36+
#### **Python**
37+
38+
```python
39+
from copilot import CopilotClient, SubprocessConfig
40+
41+
client = CopilotClient(SubprocessConfig(remote=True))
42+
session = await client.create_session(
43+
working_directory="/path/to/github-repo",
44+
on_permission_request=lambda req: {"allowed": True},
45+
)
46+
47+
def on_event(event):
48+
if event.type == "session.info" and event.data.info_type == "remote":
49+
print(f"Remote URL: {event.data.url}")
50+
51+
session.on(on_event)
52+
```
53+
54+
#### **Go**
55+
56+
```go
57+
client, _ := copilot.NewClient(&copilot.ClientOptions{Remote: true})
58+
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
59+
WorkingDirectory: "/path/to/github-repo",
60+
OnPermissionRequest: func(req copilot.PermissionRequest) copilot.PermissionResponse {
61+
return copilot.PermissionResponse{Allowed: true}
62+
},
63+
})
64+
65+
session.On(func(event copilot.SessionEvent) {
66+
if event.Type == "session.info" {
67+
// Check infoType and extract URL
68+
}
69+
})
70+
```
71+
72+
#### **C#**
73+
74+
```csharp
75+
var client = new CopilotClient(new CopilotClientOptions { Remote = true });
76+
var session = await client.CreateSessionAsync(new SessionConfig
77+
{
78+
WorkingDirectory = "/path/to/github-repo",
79+
OnPermissionRequest = async (req, ct) => new() { Allowed = true },
80+
});
81+
82+
session.On((SessionEvent e) =>
83+
{
84+
if (e is SessionInfoEvent info && info.Data.InfoType == "remote")
85+
{
86+
Console.WriteLine($"Remote URL: {info.Data.Url}");
87+
}
88+
});
89+
```
90+
91+
<!-- tabs:end -->
92+
93+
### On-demand (per-session toggle)
94+
95+
Use `session.rpc.remote.enable()` to start remote access mid-session, and `session.rpc.remote.disable()` to stop it. This is equivalent to the CLI's `/remote on` and `/remote off` commands.
96+
97+
<!-- tabs:start -->
98+
99+
#### **TypeScript**
100+
101+
```typescript
102+
const result = await session.rpc.remote.enable();
103+
console.log("Remote URL:", result.url);
104+
105+
// Later: stop sharing
106+
await session.rpc.remote.disable();
107+
```
108+
109+
#### **Python**
110+
111+
```python
112+
result = await session.rpc.remote.enable()
113+
print(f"Remote URL: {result.url}")
114+
115+
# Later: stop sharing
116+
await session.rpc.remote.disable()
117+
```
118+
119+
#### **Go**
120+
121+
```go
122+
result, err := session.RPC.Remote.Enable(ctx)
123+
fmt.Println("Remote URL:", *result.URL)
124+
125+
// Later: stop sharing
126+
err = session.RPC.Remote.Disable(ctx)
127+
```
128+
129+
#### **C#**
130+
131+
```csharp
132+
var result = await session.Rpc.Remote.EnableAsync();
133+
Console.WriteLine($"Remote URL: {result.Url}");
134+
135+
// Later: stop sharing
136+
await session.Rpc.Remote.DisableAsync();
137+
```
138+
139+
<!-- tabs:end -->
140+
141+
## QR Code Generation
142+
143+
The remote URL can be rendered as a QR code for easy mobile access. The SDK provides the URL — use your preferred QR code library:
144+
145+
- **TypeScript**: [qrcode](https://www.npmjs.com/package/qrcode)
146+
- **Python**: [qrcode](https://pypi.org/project/qrcode/)
147+
- **Go**: [go-qrcode](https://github.com/skip2/go-qrcode)
148+
- **C#**: [QRCoder](https://www.nuget.org/packages/QRCoder)
149+
150+
## Notes
151+
152+
- The `remote` client option only applies when the SDK spawns the CLI process. It is ignored when connecting to an external server via `cliUrl`.
153+
- If the working directory is not a GitHub repository, remote setup is silently skipped (always-on mode) or returns an error (on-demand mode).
154+
- Remote sessions require authentication. Ensure `gitHubToken` or `useLoggedInUser` is configured.

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Guides for building with the SDK's capabilities.
4848
- [Streaming Events](./features/streaming-events.md) — real-time event reference
4949
- [Steering & Queueing](./features/steering-and-queueing.md) — message delivery modes
5050
- [Session Persistence](./features/session-persistence.md) — resume sessions across restarts
51+
- [Remote Sessions](./features/remote-sessions.md) — share sessions to GitHub web and mobile
5152

5253
### [Hooks Reference](./hooks/index.md)
5354

dotnet/src/Client.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,11 @@ private async Task VerifyProtocolVersionAsync(Connection connection, Cancellatio
11921192
args.AddRange(["--session-idle-timeout", options.SessionIdleTimeoutSeconds.Value.ToString(CultureInfo.InvariantCulture)]);
11931193
}
11941194

1195+
if (options.Remote)
1196+
{
1197+
args.Add("--remote");
1198+
}
1199+
11951200
var (fileName, processArgs) = ResolveCliCommand(cliPath, args);
11961201

11971202
var startInfo = new ProcessStartInfo

dotnet/src/Generated/Rpc.cs

Lines changed: 95 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dotnet/src/Types.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ protected CopilotClientOptions(CopilotClientOptions? other)
7171
OnListModels = other.OnListModels;
7272
SessionFs = other.SessionFs;
7373
SessionIdleTimeoutSeconds = other.SessionIdleTimeoutSeconds;
74+
Remote = other.Remote;
7475
}
7576

7677
/// <summary>
@@ -184,6 +185,15 @@ public string? GithubToken
184185
/// </summary>
185186
public int? SessionIdleTimeoutSeconds { get; set; }
186187

188+
/// <summary>
189+
/// Enable remote session support (Mission Control integration).
190+
/// When true, sessions in a GitHub repository working directory are
191+
/// accessible from GitHub web and mobile.
192+
/// This option is only used when the SDK spawns the CLI process; it is ignored
193+
/// when connecting to an external server via <see cref="CliUrl"/>.
194+
/// </summary>
195+
public bool Remote { get; set; }
196+
187197
/// <summary>
188198
/// Creates a shallow clone of this <see cref="CopilotClientOptions"/> instance.
189199
/// </summary>

go/client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ func NewClient(options *ClientOptions) *Client {
223223
opts.CopilotHome = options.CopilotHome
224224
}
225225
opts.SessionIdleTimeoutSeconds = options.SessionIdleTimeoutSeconds
226+
opts.Remote = options.Remote
226227
}
227228

228229
// Default Env to current environment if not set
@@ -1401,6 +1402,10 @@ func (c *Client) startCLIServer(ctx context.Context) error {
14011402
args = append(args, "--session-idle-timeout", strconv.Itoa(c.options.SessionIdleTimeoutSeconds))
14021403
}
14031404

1405+
if c.options.Remote {
1406+
args = append(args, "--remote")
1407+
}
1408+
14041409
// If CLIPath is a .js file, run it with node
14051410
// Note we can't rely on the shebang as Windows doesn't support it
14061411
command := cliPath

0 commit comments

Comments
 (0)