Warning
This project is no longer actively maintained and has been discontinued. The repository will be archived, and no further updates, bug fixes, or support will be provided.
Important
This is not an officially supported Google product.
using JulesSdk;
using JulesSdk.Models;
// Set JULES_API_KEY environment variable or use 'jules config set api-key <key>'
var client = Jules.Client;
// Create an automated session
var session = await client.RunAsync(new SessionConfig
{
Prompt = "Fix the login button bug",
Source = new SourceInput("owner/repo", "main"),
AutoPr = true,
ResumeKey = "login-fix" // Optional: allows resuming this session later
});
// Stream activities as they happen
await foreach (var activity in session.StreamAsync())
{
switch (activity)
{
case PlanGeneratedActivity plan:
Console.WriteLine($"Plan: {plan.Plan.Steps.Count} steps");
break;
case AgentMessagedActivity msg:
Console.WriteLine($"Agent: {msg.Message}");
break;
case SessionCompletedActivity:
Console.WriteLine("Session complete!");
break;
}
}
// Get the result
var outcome = await session.ResultAsync();
if (outcome.PullRequest != null)
{
Console.WriteLine($"PR: {outcome.PullRequest.Url}");
}
// Or get a full snapshot with analytics
var snapshot = await session.SnapshotAsync();
Console.WriteLine(snapshot.ToMarkdown());For workflows requiring human oversight:
var session = await client.SessionAsync(new SessionConfig
{
Prompt = "Refactor the authentication module",
Source = new SourceInput("owner/repo", "develop")
});
// Wait for plan approval
await session.WaitForAsync(SessionState.AwaitingPlanApproval);
Console.WriteLine("Plan ready. Approving...");
await session.ApproveAsync();
// Ask questions
var reply = await session.AskAsync("Start with the first step");
Console.WriteLine($"Agent: {reply.Message}");
// Get final result
var outcome = await session.ResultAsync();Run sessions without a GitHub repository:
var session = await client.RunAsync(new SessionConfig
{
Prompt = "Generate a Python script that calculates fibonacci numbers"
});
var result = await session.ResultAsync();
var files = result.GeneratedFiles();
var script = files.Get("fibonacci.py");
Console.WriteLine(script?.Content);Get a point-in-time view of a session with analytics:
var session = client.Session("sessions/123");
var snapshot = await session.SnapshotAsync();
// Access computed analytics
Console.WriteLine($"Duration: {snapshot.Duration}");
Console.WriteLine($"Activities: {snapshot.Activities.Count}");
Console.WriteLine($"Plan regenerations: {snapshot.Insights.PlanRegenerations}");
Console.WriteLine($"Failed commands: {snapshot.Insights.FailedCommands.Count}");
// Export as markdown
Console.WriteLine(snapshot.ToMarkdown());
// Export as JSON with field masking
var json = snapshot.ToJson(new SnapshotSerializeOptions
{
Exclude = ["activities"] // Skip large data
});Process multiple tasks in parallel:
var tasks = new[] { "Fix login bug", "Update README", "Add tests" };
var sessions = await client.AllAsync(tasks, task => new SessionConfig
{
Prompt = task,
Source = new SourceInput("owner/repo", "main")
}, new BatchOptions { Concurrency = 3 });// Basic setup
services.AddJulesSdk(options =>
{
options.ApiKey = "your-api-key";
options.PollingIntervalMs = 3000;
});
// Or with just an API key
services.AddJulesSdk("your-api-key");
// Then inject and use
public class MyService(IJulesClient julesClient)
{
public async Task DoWorkAsync()
{
var session = await julesClient.RunAsync(new SessionConfig { ... });
}
}Cache session data locally for offline access and faster lookups:
// SQLite-based storage
var client = Jules.Connect(new JulesOptions
{
ApiKey = "your-api-key",
CacheDir = "./jules-cache" // Creates jules.db in this directory
});
// Sync sessions to local cache
var stats = await client.SyncAsync(new SyncOptions
{
Limit = 100,
Depth = SyncDepth.Activities
});
Console.WriteLine($"Synced {stats.SessionsIngested} sessions");
// Access cached data directly
var cachedSession = await client.Storage.GetSessionAsync("sessions/123");
await foreach (var activity in client.Storage.ListActivitiesAsync("sessions/123"))
{
Console.WriteLine(activity.Type);
}var client = Jules.Connect(new JulesOptions
{
ApiKey = "your-api-key",
PollingIntervalMs = 5000,
RequestTimeoutMs = 30000,
CacheDir = "./cache" // Optional: enables file-based caching
});Manage settings persistently using the jules config command:
# Set API key (stored in ~/.jules/config.json)
jules config set api-key "your-api-key"
# Set default cache directory
jules config set cache-dir "./my-cache"
# View settings
jules config get api-keyNote: The API endpoint is hardcoded to
https://jules.googleapis.com/v1alpha.
Handle code changes, media, and bash output:
await foreach (var activity in session.StreamAsync())
{
foreach (var artifact in activity.Artifacts ?? [])
{
switch (artifact)
{
case ChangeSetArtifact changeSet:
var parsed = changeSet.Parse();
Console.WriteLine($"Changed {parsed.Summary.TotalFiles} files");
foreach (var file in parsed.Files)
{
Console.WriteLine($" {file.ChangeType}: {file.Path}");
}
break;
case MediaArtifact media when media.Format.StartsWith("image/"):
await media.SaveAsync($"./screenshot-{activity.Id}.png");
break;
case BashArtifact bash:
Console.WriteLine(bash.ToString());
break;
}
}
}- .NET 8.0, 9.0, or 10.0
- Valid Jules API key
Apache-2.0