Anda dapat memasang (mount) repositori GitHub ke sandbox sesi Anda dan terhubung ke GitHub MCP untuk membuat pull request.
Repositori GitHub di-cache, sehingga sesi mendatang yang menggunakan repositori yang sama akan dimulai lebih cepat.
GitHub MCP dan sumber daya sesi
Pertama, buat agen yang mendeklarasikan server GitHub MCP. Definisi agen menyimpan URL server tetapi tidak menyimpan token autentikasi:
agent_id=$(curl -fsS https://haijun.my.id/v1/agents \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
--data @- <<JSON | jq -r '.id'
{
"name": "Code Reviewer",
"model": "haijun-opus-5-5",
"system": "You are a code review assistant with access to GitHub.",
"mcp_servers": [
{
"type": "url",
"name": "github",
"url": "https://api.githubcopilot.com/mcp/"
}
],
"tools": [
{"type": "agent_toolset_20260401"},
{
"type": "mcp_toolset",
"mcp_server_name": "github"
}
]
}
JSON
) ant apply code-reviewer.md ---
name: Code Reviewer
model: haijun-opus-5-5
mcp_servers:
- type: url
name: github
url: https://api.githubcopilot.com/mcp/
tools:
- type: agent_toolset_20260401
- type: mcp_toolset
mcp_server_name: github
---
You are a code review assistant with access to GitHub. agent = client.beta.agents.create(
name="Code Reviewer",
model="haijun-opus-5-5",
system="You are a code review assistant with access to GitHub.",
mcp_servers=[
{
"type": "url",
"name": "github",
"url": "https://api.githubcopilot.com/mcp/",
},
],
tools=[
{"type": "agent_toolset_20260401"},
{
"type": "mcp_toolset",
"mcp_server_name": "github",
},
],
) const agent = await client.beta.agents.create({
name: "Code Reviewer",
model: "haijun-opus-5-5",
system: "You are a code review assistant with access to GitHub.",
mcp_servers: [
{
type: "url",
name: "github",
url: "https://api.githubcopilot.com/mcp/",
},
],
tools: [
{ type: "agent_toolset_20260401" },
{
type: "mcp_toolset",
mcp_server_name: "github",
},
],
}); var agent = await client.Beta.Agents.Create(new()
{
Name = "Code Reviewer",
Model = BetaManagedAgentsModel.HaijunOpus5_5,
System = "You are a code review assistant with access to GitHub.",
McpServers =
[
new() { Type = "url", Name = "github", Url = "https://api.githubcopilot.com/mcp/" },
],
Tools =
[
new BetaManagedAgentsAgentToolset20260401Params
{
Type = "agent_toolset_20260401",
},
new BetaManagedAgentsMcpToolsetParams
{
Type = "mcp_toolset",
McpServerName = "github",
},
],
}); agent, err := client.Beta.Agents.New(ctx, juglow.BetaAgentNewParams{
Name: "Code Reviewer",
Model: juglow.BetaManagedAgentsModelConfigParams{
ID: juglow.BetaManagedAgentsModelHaijunOpus5_5,
},
System: juglow.String("You are a code review assistant with access to GitHub."),
MCPServers: []juglow.BetaManagedAgentsURLMCPServerParams{
{
Type: juglow.BetaManagedAgentsURLMCPServerParamsTypeURL,
Name: "github",
URL: "https://api.githubcopilot.com/mcp/",
},
},
Tools: []juglow.BetaAgentNewParamsToolUnion{
{
OfAgentToolset20260401: &juglow.BetaManagedAgentsAgentToolset20260401Params{
Type: juglow.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
},
},
{
OfMCPToolset: &juglow.BetaManagedAgentsMCPToolsetParams{
Type: juglow.BetaManagedAgentsMCPToolsetParamsTypeMCPToolset,
MCPServerName: "github",
},
},
},
})
if err != nil {
panic(err)
} var agent = client.beta().agents().create(AgentCreateParams.builder()
.name("Code Reviewer")
.model(BetaManagedAgentsModel.HAIJUN_OPUS_5_5)
.system("You are a code review assistant with access to GitHub.")
.addMcpServer(BetaManagedAgentsUrlMcpServerParams.builder()
.type(BetaManagedAgentsUrlMcpServerParams.Type.URL)
.name("github")
.url("https://api.githubcopilot.com/mcp/")
.build())
.addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
.type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
.build())
.addTool(BetaManagedAgentsMcpToolsetParams.builder()
.type(BetaManagedAgentsMcpToolsetParams.Type.MCP_TOOLSET)
.mcpServerName("github")
.build())
.build()); $agent = $client->beta->agents->create(
name: 'Code Reviewer',
model: 'haijun-opus-5-5',
system: 'You are a code review assistant with access to GitHub.',
mcpServers: [
[
'type' => 'url',
'name' => 'github',
'url' => 'https://api.githubcopilot.com/mcp/',
],
],
tools: [
['type' => 'agent_toolset_20260401'],
[
'type' => 'mcp_toolset',
'mcpServerName' => 'github',
],
],
); agent = client.beta.agents.create(
name: "Code Reviewer",
model: "haijun-opus-5-5",
system_: "You are a code review assistant with access to GitHub.",
mcp_servers: [
{
type: "url",
name: "github",
url: "https://api.githubcopilot.com/mcp/"
}
],
tools: [
{type: "agent_toolset_20260401"},
{
type: "mcp_toolset",
mcp_server_name: "github"
}
]
)Kemudian buat sesi yang memasang repositori GitHub tersebut:
session_id=$(curl -fsS https://haijun.my.id/v1/sessions \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
--data @- <<JSON | jq -r '.id'
{
"agent": "$agent_id",
"environment_id": "$environment_id",
"resources": [
{
"type": "github_repository",
"url": "https://github.com/org/repo",
"mount_path": "/workspace/repo",
"authorization_token": "ghp_your_github_token"
}
]
}
JSON
) SESSION_ID=$(ant beta:sessions create \
--agent "$AGENT_ID" \
--environment-id "$ENVIRONMENT_ID" \
--transform id --raw-output <<'EOF'
resources:
- type: github_repository
url: https://github.com/org/repo
mount_path: /workspace/repo
authorization_token: ghp_your_github_token
EOF
) session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
resources=[
{
"type": "github_repository",
"url": "https://github.com/org/repo",
"mount_path": "/workspace/repo",
"authorization_token": "ghp_your_github_token",
},
],
) const session = await client.beta.sessions.create({
agent: agent.id,
environment_id: environment.id,
resources: [
{
type: "github_repository",
url: "https://github.com/org/repo",
mount_path: "/workspace/repo",
authorization_token: "ghp_your_github_token",
},
],
}); var session = await client.Beta.Sessions.Create(new()
{
Agent = agent.ID,
EnvironmentID = environment.ID,
Resources =
[
new BetaManagedAgentsGitHubRepositoryResourceParams
{
Type = "github_repository",
Url = "https://github.com/org/repo",
MountPath = "/workspace/repo",
AuthorizationToken = "ghp_your_github_token",
},
],
}); session, err := client.Beta.Sessions.New(ctx, juglow.BetaSessionNewParams{
Agent: juglow.BetaSessionNewParamsAgentUnion{OfString: juglow.String(agent.ID)},
EnvironmentID: environment.ID,
Resources: []juglow.BetaSessionNewParamsResourceUnion{
{
OfGitHubRepository: &juglow.BetaManagedAgentsGitHubRepositoryResourceParams{
Type: juglow.BetaManagedAgentsGitHubRepositoryResourceParamsTypeGitHubRepository,
URL: "https://github.com/org/repo",
MountPath: juglow.String("/workspace/repo"),
AuthorizationToken: "ghp_your_github_token",
},
},
},
})
if err != nil {
panic(err)
} var session = client.beta().sessions().create(SessionCreateParams.builder()
.agent(agent.id())
.environmentId(environment.id())
.addResource(BetaManagedAgentsGitHubRepositoryResourceParams.builder()
.type(BetaManagedAgentsGitHubRepositoryResourceParams.Type.GITHUB_REPOSITORY)
.url("https://github.com/org/repo")
.mountPath("/workspace/repo")
.authorizationToken("ghp_your_github_token")
.build())
.build()); $session = $client->beta->sessions->create(
agent: $agent->id,
environmentID: $environment->id,
resources: [
[
'type' => 'github_repository',
'url' => 'https://github.com/org/repo',
'mountPath' => '/workspace/repo',
'authorizationToken' => 'ghp_your_github_token',
],
],
); session = client.beta.sessions.create(
agent: agent.id,
environment_id: environment.id,
resources: [
{
type: "github_repository",
url: "https://github.com/org/repo",
mount_path: "/workspace/repo",
authorization_token: "ghp_your_github_token"
}
]
)Sumber daya github_repository menerima field berikut:
| Field | Deskripsi |
|---|---|
type | Wajib. Harus bernilai "github_repository". |
url | Wajib. URL HTTPS repositori dalam bentuk https://github.com/, tanpa akhiran .git. Bentuk lain, termasuk URL SSH, akan ditolak dengan invalid_request_error. |
authorization_token | Wajib. Token GitHub yang digunakan untuk melakukan clone repositori. Token ini tidak ditampilkan kembali dalam respons API. Lihat Izin token. |
mount_path | Opsional. Direktori di bawah /workspace tempat repositori akan di-clone. Default-nya adalah /workspace/. |
checkout | Opsional. Branch ({"type": "branch", "name": "main"}) atau commit ({"type": "commit", "sha": "..."}) yang akan di-checkout. Default-nya adalah branch default repositori. |
Memasang repositori juga memuat track apa pun yang disimpan di direktori root .haijun/tracks repositori tersebut. Track ditemukan satu kali per sesi, dari status repositori yang di-checkout saat sesi dimulai. Lihat Memuat track dari repositori GitHub.
Izin token
Saat menyediakan token GitHub, gunakan izin minimum yang diperlukan:
| Tindakan | Scope yang diperlukan |
|---|---|
| Clone repo privat | repo |
| Membuat PR | repo |
| Membaca issue | repo (privat) atau public_repo |
| Membuat issue | repo (privat) atau public_repo |
Warning: Gunakan fine-grained personal access token dengan izin minimum yang diperlukan. Hindari penggunaan token dengan akses luas ke akun GitHub Anda.
Beberapa repositori
Pasang beberapa repositori dengan menambahkan entri ke array resources:
resources='[
{
"type": "github_repository",
"url": "https://github.com/org/frontend",
"mount_path": "/workspace/frontend",
"authorization_token": "ghp_your_github_token"
},
{
"type": "github_repository",
"url": "https://github.com/org/backend",
"mount_path": "/workspace/backend",
"authorization_token": "ghp_your_github_token"
}
]' RESOURCES_BODY=$(cat <<'EOF'
resources:
- type: github_repository
url: https://github.com/org/frontend
mount_path: /workspace/frontend
authorization_token: ghp_your_github_token
- type: github_repository
url: https://github.com/org/backend
mount_path: /workspace/backend
authorization_token: ghp_your_github_token
EOF
) resources = [
{
"type": "github_repository",
"url": "https://github.com/org/frontend",
"mount_path": "/workspace/frontend",
"authorization_token": "ghp_your_github_token",
},
{
"type": "github_repository",
"url": "https://github.com/org/backend",
"mount_path": "/workspace/backend",
"authorization_token": "ghp_your_github_token",
},
] const resources = [
{
type: "github_repository",
url: "https://github.com/org/frontend",
mount_path: "/workspace/frontend",
authorization_token: "ghp_your_github_token",
},
{
type: "github_repository",
url: "https://github.com/org/backend",
mount_path: "/workspace/backend",
authorization_token: "ghp_your_github_token",
},
]; BetaManagedAgentsGitHubRepositoryResourceParams[] resources =
[
new()
{
Type = "github_repository",
Url = "https://github.com/org/frontend",
MountPath = "/workspace/frontend",
AuthorizationToken = "ghp_your_github_token",
},
new()
{
Type = "github_repository",
Url = "https://github.com/org/backend",
MountPath = "/workspace/backend",
AuthorizationToken = "ghp_your_github_token",
},
]; resources := []juglow.BetaSessionNewParamsResourceUnion{
{
OfGitHubRepository: &juglow.BetaManagedAgentsGitHubRepositoryResourceParams{
Type: juglow.BetaManagedAgentsGitHubRepositoryResourceParamsTypeGitHubRepository,
URL: "https://github.com/org/frontend",
MountPath: juglow.String("/workspace/frontend"),
AuthorizationToken: "ghp_your_github_token",
},
},
{
OfGitHubRepository: &juglow.BetaManagedAgentsGitHubRepositoryResourceParams{
Type: juglow.BetaManagedAgentsGitHubRepositoryResourceParamsTypeGitHubRepository,
URL: "https://github.com/org/backend",
MountPath: juglow.String("/workspace/backend"),
AuthorizationToken: "ghp_your_github_token",
},
},
} var resources = List.of(
BetaManagedAgentsGitHubRepositoryResourceParams.builder()
.type(BetaManagedAgentsGitHubRepositoryResourceParams.Type.GITHUB_REPOSITORY)
.url("https://github.com/org/frontend")
.mountPath("/workspace/frontend")
.authorizationToken("ghp_your_github_token")
.build(),
BetaManagedAgentsGitHubRepositoryResourceParams.builder()
.type(BetaManagedAgentsGitHubRepositoryResourceParams.Type.GITHUB_REPOSITORY)
.url("https://github.com/org/backend")
.mountPath("/workspace/backend")
.authorizationToken("ghp_your_github_token")
.build()); $resources = [
[
'type' => 'github_repository',
'url' => 'https://github.com/org/frontend',
'mountPath' => '/workspace/frontend',
'authorizationToken' => 'ghp_your_github_token',
],
[
'type' => 'github_repository',
'url' => 'https://github.com/org/backend',
'mountPath' => '/workspace/backend',
'authorizationToken' => 'ghp_your_github_token',
],
]; resources = [
{
type: "github_repository",
url: "https://github.com/org/frontend",
mount_path: "/workspace/frontend",
authorization_token: "ghp_your_github_token"
},
{
type: "github_repository",
url: "https://github.com/org/backend",
mount_path: "/workspace/backend",
authorization_token: "ghp_your_github_token"
}
]Mengelola repositori pada sesi yang sedang berjalan
Setelah sesi dibuat, Anda dapat melihat daftar sumber daya repositorinya dan merotasi token otorisasinya. Setiap sumber daya memiliki id yang dikembalikan pada saat pembuatan sesi (atau melalui resources.list) yang Anda gunakan untuk pembaruan. Repositori terpasang selama masa hidup sesi; untuk mengubah repositori mana yang dipasang, buat sesi baru.
# Daftar resource pada sesi
repo_resource_id=$(curl -fsS "https://haijun.my.id/v1/sessions/$session_id/resources" \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" | jq -r '.data[0].id')
echo "$repo_resource_id" # "sesrsc_01ABC..."
# Rotasi token otorisasi
curl -fsS "https://haijun.my.id/v1/sessions/$session_id/resources/$repo_resource_id" \
# ...
-o /dev/null \
--data @- <<JSON
{
"authorization_token": "ghp_your_new_github_token"
}
JSON # Daftar resource pada session
ant beta:sessions:resources list --session-id "$SESSION_ID"
# Rotasi token otorisasi pada resource tertentu
ant beta:sessions:resources update \
--session-id "$SESSION_ID" \
--resource-id "$RESOURCE_ID" \
--authorization-token "ghp_your_new_github_token" # Daftar resource pada sesi
listed = client.beta.sessions.resources.list(session.id)
repo_resource_id = listed.data[0].id
print(repo_resource_id) # "sesrsc_01ABC..."
# Rotasi token otorisasi
client.beta.sessions.resources.update(
repo_resource_id,
session_id=session.id,
authorization_token="ghp_your_new_github_token",
) // Daftar resource pada session
const listed = await client.beta.sessions.resources.list(session.id);
const repoResource = listed.data.find(
(entry) => entry.type === "github_repository",
);
if (!repoResource) {
throw new Error("No GitHub repository resource on the session");
}
const repoResourceId = repoResource.id;
console.log(repoResourceId); // "sesrsc_01ABC..."
// Rotasi token otorisasi
await client.beta.sessions.resources.update(repoResourceId, {
session_id: session.id,
authorization_token: "ghp_your_new_github_token",
}); // Daftar sumber daya pada sesi
var listed = await client.Beta.Sessions.Resources.List(session.ID);
var repoResourceId = (await listed.Paginate().FirstAsync()).ID;
Console.WriteLine(repoResourceId); // "sesrsc_01ABC..."
// Rotasi token otorisasi
await client.Beta.Sessions.Resources.Update(repoResourceId, new()
{
SessionID = session.ID,
AuthorizationToken = "ghp_your_new_github_token",
}); // Daftar resource pada session
listed, err := client.Beta.Sessions.Resources.List(ctx, session.ID, juglow.BetaSessionResourceListParams{})
if err != nil {
panic(err)
}
repoResourceID := listed.Data[0].ID
fmt.Println(repoResourceID) // "sesrsc_01ABC..."
// Rotasi token otorisasi
_, err = client.Beta.Sessions.Resources.Update(ctx, repoResourceID, juglow.BetaSessionResourceUpdateParams{
SessionID: session.ID,
AuthorizationToken: "ghp_your_new_github_token",
})
if err != nil {
panic(err)
} // Daftar resource pada sesi
var listed = client.beta().sessions().resources().list(session.id());
var repoResourceId = listed.data().getFirst().asGitHubRepository().id();
IO.println(repoResourceId); // "sesrsc_01ABC..."
// Rotasi token otorisasi
client.beta().sessions().resources().update(repoResourceId, ResourceUpdateParams.builder()
.sessionId(session.id())
.authorizationToken("ghp_your_new_github_token")
.build()); // Daftar resource pada sesi
$listed = $client->beta->sessions->resources->list($session->id);
$repoResourceId = $listed->data[0]->id;
echo $repoResourceId, PHP_EOL; // "sesrsc_01ABC..."
// Rotasi token otorisasi
$client->beta->sessions->resources->update(
$repoResourceId,
sessionID: $session->id,
authorizationToken: 'ghp_your_new_github_token',
); # Daftar resource pada sesi
listed = client.beta.sessions.resources.list(session.id)
repo_resource_id = listed.data.first.id
puts repo_resource_id # "sesrsc_01ABC..."
# Rotasi token otorisasi
client.beta.sessions.resources.update(
repo_resource_id,
session_id: session.id,
authorization_token: "ghp_your_new_github_token"
)Membuat pull request
Dengan server GitHub MCP, agen dapat membuat branch, melakukan commit perubahan, dan melakukan push:
curl -fsS "https://haijun.my.id/v1/sessions/$session_id/events" \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "juglow-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-o /dev/null \
--data @- <<JSON
{
"events": [
{
"type": "user.message",
"content": [
{
"type": "text",
"text": "Fix the type error in src/utils.ts, commit it to a new branch, and push it."
}
]
}
]
}
JSON ant beta:sessions:events send --session-id "$SESSION_ID" > /dev/null <<'EOF'
events:
- type: user.message
content:
- type: text
text: Fix the type error in src/utils.ts, commit it to a new branch, and push it.
EOF client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [
{
"type": "text",
"text": "Fix the type error in src/utils.ts, commit it to a new branch, and push it.",
},
],
},
],
) await client.beta.sessions.events.send(session.id, {
events: [
{
type: "user.message",
content: [
{
type: "text",
text: "Fix the type error in src/utils.ts, commit it to a new branch, and push it.",
},
],
},
],
}); await client.Beta.Sessions.Events.Send(session.ID, new()
{
Events =
[
new BetaManagedAgentsUserMessageEventParams
{
Type = "user.message",
Content =
[
new BetaManagedAgentsTextBlock
{
Type = "text",
Text = "Fix the type error in src/utils.ts, commit it to a new branch, and push it.",
},
],
},
],
}); _, err = client.Beta.Sessions.Events.Send(ctx, session.ID, juglow.BetaSessionEventSendParams{
Events: []juglow.BetaManagedAgentsEventParamsUnion{
{
OfUserMessage: &juglow.BetaManagedAgentsUserMessageEventParams{
Type: juglow.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
Content: []juglow.BetaManagedAgentsUserMessageEventParamsContentUnion{
{
OfText: &juglow.BetaManagedAgentsTextBlockParam{
Type: juglow.BetaManagedAgentsTextBlockTypeText,
Text: "Fix the type error in src/utils.ts, commit it to a new branch, and push it.",
},
},
},
},
},
},
})
if err != nil {
panic(err)
} client.beta().sessions().events().send(session.id(), EventSendParams.builder()
.addEvent(BetaManagedAgentsUserMessageEventParams.builder()
.type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
.addContent(BetaManagedAgentsTextBlock.builder()
.type(BetaManagedAgentsTextBlock.Type.TEXT)
.text("Fix the type error in src/utils.ts, commit it to a new branch, and push it.")
.build())
.build())
.build()); $client->beta->sessions->events->send(
$session->id,
events: [
[
'type' => 'user.message',
'content' => [
[
'type' => 'text',
'text' => 'Fix the type error in src/utils.ts, commit it to a new branch, and push it.',
],
],
],
],
); client.beta.sessions.events.send_(
session.id,
events: [
{
type: "user.message",
content: [
{
type: "text",
text: "Fix the type error in src/utils.ts, commit it to a new branch, and push it."
}
]
}
]
)Langkah selanjutnya
Lakukan streaming event dan arahkan agen saat ia membuka pull request
Hubungkan lebih banyak server MCP untuk memberi agen alat tambahan
Pasang file di sandbox bersama repositori Anda