Skip to main content

Optional AI providers

SHAFT Pilot separates provider-neutral contracts from optional direct model access:

  • shaft-pilot-core contains immutable request/response records, approval and redaction policies, budgets, safe audit metadata, provider capabilities, ServiceLoader discovery, and deterministic fallback.
  • shaft-ai contains direct HTTP adapters for OpenAI, Anthropic, Google Gemini, GitHub Models, and local Ollama. It uses JDK HttpClient; no provider SDK type is exposed.
  • shaft-engine exposes only thread-local SHAFT.Properties.pilot configuration. It has no dependency on either Pilot module.

shaft-capture and shaft-doctor depend on shaft-pilot-core. Add shaft-ai only when direct provider calls are required. Capture creation, validation, migration, and redaction remain deterministic with pilot.ai.enabled=false.

SHAFT Doctor uses these contracts for an optional separately rendered advisory. It submits only minimized evidence from an already-redacted EvidenceBundle plus the deterministic diagnosis. Provider output cannot replace the baseline, must cite only submitted evidence IDs, and falls back safely for provider, budget, timeout, or validation failures. See SHAFT Doctor.

Safe defaults

AI is off unless both settings are changed:

pilot.ai.enabled=false
pilot.ai.provider=none

Provider models default to blank except pilot.ai.gemini.model, which defaults to gemini-3.5-flash; remote and local consent default to false, and no evidence category is approved by default. Disabled or unavailable AI returns the request's deterministicFallback and makes no network call.

Credentials are read only from environment variables:

ProviderDefault variable
OpenAIOPENAI_API_KEY
AnthropicANTHROPIC_API_KEY
GeminiGEMINI_API_KEY
GitHub ModelsGITHUB_TOKEN
Ollamanone

The environment variable names are configurable, but credential values are never SHAFT properties. Provider endpoints and models are configured through SHAFT.Properties.pilot; no model is selected implicitly.

Managed local preview

The optional shaft-ai module also contains SHAFT's managed-local provider. Set managedLocalAi.enabled=true to select it for the current thread and grant local-processing consent. The property defaults to false. This setting does not grant remote or on-premises consent, and the provider does not require a credential or caller-selected endpoint. The pin table on the setup page is the documented inventory for revision, license, provenance, size, storage class, resource floors, update policy, cleanup rule, and deterministic fallback. setup status and setup verify print target readiness version detail (version empty unless READY) and report readiness/version/action; see managed local AI inventory.

Use the review-first configuration while evaluating it:

src/main/resources/properties/custom.properties
managedLocalAi.enabled=true
managedLocalAi.transparentProvisioning=false
managedLocalAi.model=qwen3-0.6b-q8_0

Provision and maintain the reviewed runtime/model pair through the managed local AI setup flow. Set managedLocalAi.transparentProvisioning=true only when an approved request may provision a missing reviewed pair without a separate CLI install phase.

The compact candidate is manual-only because its current recommendation-quality benchmark failed. Keep the request's deterministic fallback authoritative; do not use this preview to enable automatic advisory decisions.

Approval and evidence

Every request carries an ApprovalPolicy, and the effective SHAFT properties must independently approve the same processing location and all submitted EvidenceCategory values. Remote calls require pilot.ai.consent.remote=true. Ollama requires pilot.ai.consent.local=true; a loopback endpoint is not trusted automatically.

Before provider execution, AiExecutionService:

  1. checks provider capabilities and availability;
  2. enforces request size, token, cost, timeout, concurrency, and circuit-breaker limits;
  3. rejects unapproved evidence categories;
  4. redacts authorization and cookie headers, password/secret assignments, common tokens, configured DOM selectors, attributes, and patterns;
  5. validates provider JSON against the requested schema;
  6. returns deterministic fallback for every failure.

Audit events contain only request ID, purpose, provider/model identifiers, redaction counts, duration, and status. Prompts, evidence, credentials, raw responses, and original secret values are excluded.

Example

SHAFT.Properties.pilot.set()
.enabled(true)
.provider("ollama")
.localConsent(true)
.allowedEvidenceCategories("TEXT")
.ollamaModel("your-local-model");

var schema = JsonNodeFactory.instance.objectNode()
.put("type", "object");
schema.putObject("properties")
.putObject("summary")
.put("type", "string");
schema.putArray("required").add("summary");

var approval = new ApprovalPolicy(
true,
false,
Set.of(EvidenceCategory.TEXT));

var request = AiRequest.builder("doctor-summary", schema)
.text(redactedDiagnosticText)
.approvalPolicy(approval)
.deterministicFallback(deterministicDiagnosis)
.build();

AiResponse response = new AiExecutionService().execute(request);

Call SHAFT.Properties.clearForCurrentThread() at lifecycle boundaries after setting per-thread Pilot properties.

Direct providers and external agents

Direct provider adapters are separate from MCP clients. OpenAI, Anthropic, Gemini, and GitHub Models credentials apply only to shaft-ai direct calls. GitHub/Microsoft Copilot is supported through SHAFT MCP and retains its own client authentication; SHAFT does not request or define a generic Copilot model API key.

Credential-free MCP configuration fixtures are under the downloadable Pilot example assets. See SHAFT MCP for transport and deployment details. The representative doctor_analyze fixture covers ChatGPT, Codex, Claude, Gemini, and GitHub Copilot without embedding any client or provider credential.

Provider request mappings follow the official OpenAI structured output, Anthropic structured output, Gemini structured output, GitHub Models, and Ollama chat contracts.