-
Notifications
You must be signed in to change notification settings - Fork 0
ExternalEngine
Register and manage external analysis engines for use on Lichess.
Namespace: LichessSharp.Api.Contracts
Access: client.ExternalEngine
Warning: This API is in alpha and subject to change.
The External Engine API allows you to:
- Register custom chess engines to use on Lichess
- Provide analysis through a provider service
- Request analysis from registered engines
This is useful for:
- Running powerful engines locally while analyzing on Lichess
- Providing specialized analysis engines
- Using engines not available on Lichess servers
List all external engines registered for the authenticated user.
Required Scope: engine:read
Task<IReadOnlyList<ExternalEngine>> ListAsync(CancellationToken cancellationToken = default)Example:
using var client = new LichessClient(token);
var engines = await client.ExternalEngine.ListAsync();
Console.WriteLine($"Registered engines ({engines.Count}):\n");
foreach (var engine in engines)
{
Console.WriteLine($"Name: {engine.Name}");
Console.WriteLine($" ID: {engine.Id}");
Console.WriteLine($" Max Threads: {engine.MaxThreads}");
Console.WriteLine($" Max Hash: {engine.MaxHash} MB");
Console.WriteLine($" Variants: {string.Join(", ", engine.Variants)}");
Console.WriteLine();
}Register a new external engine.
Required Scope: engine:write
Task<ExternalEngine> CreateAsync(
ExternalEngineRegistration registration,
CancellationToken cancellationToken = default)Example:
using var client = new LichessClient(token);
var engine = await client.ExternalEngine.CreateAsync(new ExternalEngineRegistration
{
Name = "My Custom Stockfish",
MaxThreads = 8,
MaxHash = 4096,
ProviderSecret = "your-secret-key-at-least-16-chars",
Variants = new[] { "standard", "chess960" },
ProviderData = "my-local-engine-v1"
});
Console.WriteLine($"Engine registered!");
Console.WriteLine($" ID: {engine.Id}");
Console.WriteLine($" Client Secret: {engine.ClientSecret}");
// Store the client secret securely - you'll need it for analysis requestsGet details of a specific external engine.
Required Scope: engine:read
Task<ExternalEngine> GetAsync(string engineId, CancellationToken cancellationToken = default)Update an existing external engine.
Required Scope: engine:write
Task<ExternalEngine> UpdateAsync(
string engineId,
ExternalEngineRegistration registration,
CancellationToken cancellationToken = default)Example:
using var client = new LichessClient(token);
var updated = await client.ExternalEngine.UpdateAsync("engineId", new ExternalEngineRegistration
{
Name = "My Upgraded Stockfish",
MaxThreads = 16,
MaxHash = 8192,
ProviderSecret = "your-secret-key-at-least-16-chars",
Variants = new[] { "standard", "chess960", "atomic" }
});Delete an external engine.
Required Scope: engine:write
Task DeleteAsync(string engineId, CancellationToken cancellationToken = default)Request analysis from an external engine. Streams analysis lines as they're computed.
IAsyncEnumerable<EngineAnalysisLine> AnalyseAsync(
string engineId,
EngineAnalysisRequest request,
CancellationToken cancellationToken = default)Example:
using var client = new LichessClient(token);
var request = new EngineAnalysisRequest
{
ClientSecret = "your-client-secret",
Work = new EngineAnalysisWork
{
SessionId = "my-session",
Threads = 4,
Hash = 1024,
MultiPv = 3,
InitialFen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1",
Moves = new[] { "e7e5", "g1f3" },
InfiniteDepth = 30
}
};
await foreach (var line in client.ExternalEngine.AnalyseAsync("engineId", request))
{
if (line.Pv != null)
{
var evalStr = line.Score?.Centipawns.HasValue == true
? $"cp {line.Score.Centipawns}"
: $"mate {line.Score?.Mate}";
Console.WriteLine($"depth {line.Depth} {evalStr} pv {line.Pv}");
}
}To provide analysis, your engine service needs to:
- Poll for work using
AcquireWorkAsync - Submit analysis results using
SubmitWorkAsync
Wait for an analysis request (long polling).
Task<EngineWork?> AcquireWorkAsync(
string providerSecret,
CancellationToken cancellationToken = default)Submit analysis results for acquired work.
Task SubmitWorkAsync(
string workId,
IAsyncEnumerable<string> uciLines,
CancellationToken cancellationToken = default)Provider Example:
using var client = new LichessClient();
var providerSecret = "your-provider-secret";
// Engine provider loop
while (!cancellationToken.IsCancellationRequested)
{
// Wait for work (long polling)
var work = await client.ExternalEngine.AcquireWorkAsync(providerSecret, cancellationToken);
if (work == null)
continue;
Console.WriteLine($"Got work: {work.Id}");
Console.WriteLine($" Position: {work.Work.InitialFen}");
Console.WriteLine($" Moves: {string.Join(" ", work.Work.Moves ?? [])}");
// Run your engine and stream UCI output
var uciOutput = RunEngine(work.Work);
await client.ExternalEngine.SubmitWorkAsync(work.Id, uciOutput, cancellationToken);
}
async IAsyncEnumerable<string> RunEngine(EngineWorkDetails work)
{
// Start your UCI engine and send commands
// Example output:
yield return "info depth 10 score cp 25 pv e2e4 e7e5";
yield return "info depth 15 score cp 30 pv e2e4 e7e5 g1f3";
yield return "bestmove e2e4";
}| Property | Type | Description |
|---|---|---|
| Name | string | Display name (3-200 chars) |
| MaxThreads | int | Max threads available (1-65536) |
| MaxHash | int | Max hash table size in MiB (1-1048576) |
| ProviderSecret | string | Secret for provider auth (min 16 chars) |
| Variants | IReadOnlyList<string>? | Supported variants |
| ProviderData | string? | Arbitrary provider data |
| Property | Type | Description |
|---|---|---|
| SessionId | string? | Session identifier |
| Threads | int? | Threads to use |
| Hash | int? | Hash table size (MiB) |
| MultiPv | int? | Principal variations (1-5) |
| Variant | string? | Chess variant |
| InitialFen | string | Starting FEN |
| Moves | IReadOnlyList<string>? | UCI moves from initial position |
| InfiniteDepth | int? | Depth limit |
| Nodes | long? | Node limit |
| MoveTime | int? | Time limit (ms) |
| Property | Type | Description |
|---|---|---|
| Id | string | Engine registration ID |
| Name | string | Display name |
| ClientSecret | string | Secret for analysis requests |
| UserId | string | Owner's user ID |
| MaxThreads | int | Max available threads |
| MaxHash | int | Max hash size (MiB) |
| Variants | IReadOnlyList<string> | Supported variants |
| ProviderData | string? | Provider data |
| Property | Type | Description |
|---|---|---|
| Time | int? | Analysis time (ms) |
| Depth | int? | Search depth |
| SelDepth | int? | Selective depth |
| Nodes | long? | Nodes searched |
| Pv | string? | Principal variation |
| Score | EngineScore? | Evaluation |
| CurrentMove | string? | Move being searched |
| CurrentMoveNumber | int? | Current move number |
| HashFull | int? | Hash table usage (per mille) |
| Nps | long? | Nodes per second |
| TbHits | long? | Tablebase hits |
| MultiPv | int? | PV line number (1-indexed) |
| Property | Type | Description |
|---|---|---|
| Centipawns | int? | Score in centipawns |
| Mate | int? | Mate in N moves |
- Analysis API - Cloud evaluations
- OAuth API - Authentication for scopes