DelphiCompileGate is an Open Tools API (OTA) plugin for Delphi 13 Community Edition. It compiles Delphi projects with the compiler hosted inside the IDE. Builds are submitted through a Python API and return validated compiler, target, dialog, and artifact evidence.
DelphiCompileGateClient.compile_project()is the only supported compile API and the only supported producer of queue jobs.- Callers provide an absolute
.dpror.dpkfile and may provide the same-directory, same-stem.dprojfile. - Requests and results are validated against exact schemas, hashes, paths, identities, and target evidence. Missing or contradictory evidence fails closed.
DelphiCompileGate/
|-- Package/
| |-- DelphiCompileGate.dpk
| `-- DelphiCompileGate.dproj
|-- Src/
| |-- DelphiCompileGate.BuildInfo.pas
| |-- DelphiCompileGate.Compiler.pas
| |-- DelphiCompileGate.Consts.pas
| |-- DelphiCompileGate.MessageHook.pas
| |-- DelphiCompileGate.ProtocolV2.pas
| |-- DelphiCompileGate.Register.pas
| |-- DelphiCompileGate.Settings.pas
| |-- DelphiCompileGate.SettingsDialog.pas
| |-- DelphiCompileGate.Watch.pas
| `-- DelphiCompileGate.Wizard.pas
|-- delphi_compile_gate.py
|-- AGENTS.md
|-- ASSISTANT_GUIDE.md
|-- KNOWN_ISSUES.md
`-- README.md
For complete prerequisites, package build, verification, update, uninstall, and
troubleshooting instructions, see INSTALLATION.md.
- Start Delphi 13 Community Edition.
- Open
Package\DelphiCompileGate.dpkin the IDE. - Compile the package with
Ctrl+F9. - Select Install in the package editor.
- Open Help > Help Wizards > Delphi Compile Gate Settings / Status.... In a German IDE, use Hilfe > Hilfe-Experten > Delphi Compile Gate Settings / Status....
- Select Start Watch, then select OK. The watcher starts only after this user action and a successful OK save; it does not start with the IDE.
After changing any Pascal source, rebuild and reinstall the package in the IDE.
Changing the checkout does not update the loaded BPL. The loaded instance must
report plugin version 2.0.0, Protocol 2, and build ID
dcg-v2-20260904-releaseprep-02.
Paste the following prompt into an AI coding assistant before asking it to create or modify Delphi code in a workspace:
Read AGENTS.md in the DelphiCompileGate repository before editing or compiling
Delphi code. Follow it as the authoritative compile contract.
Use only DelphiCompileGateClient.compile_project(). Never invoke dcc32, MSBuild,
or another external Delphi compiler, and never create queue manifests manually.
Find the workspace's existing .dpr or .dpk. If a same-directory, same-stem
.dproj already exists, pass both files to compile_project(). If no matching
.dproj exists, pass only the .dpr or .dpk; DelphiCompileGate creates its managed
temporary .dproj automatically. Never create, guess, or edit a .dproj merely to
use DelphiCompileGate.
Compile after making changes. Use only platform Win32 or Win64 and configuration
Debug or Release. Accept success only when status is "ok", success is true,
compile.target_matched is true, compile.release_eligible is true, and
interventions.policy_compliant is true. Otherwise report the exact failure_code
and compiler diagnostics.
Delphi 13 Community Edition must already be running with the current
DelphiCompileGate package installed. The watcher must show Running, and the
Settings / Status dialog must be closed while waiting for a result. If those
conditions are not met, report the prerequisite instead of using another
compiler.
The prompt is intentionally self-contained so a weak assistant cannot infer an
obsolete API or invent a project file. AGENTS.md contains the complete rules
and copy-ready Python examples.
By default, both the plugin and client use
%LOCALAPPDATA%\DelphiCompileGate\Run. If LOCALAPPDATA is unavailable, they
use %USERPROFILE%\AppData\Local\DelphiCompileGate\Run, then the system temp
directory. To use another shared runtime base, set this variable before
starting Delphi and the client:
DELPHI_COMPILE_GATE_BASE_DIR=C:\Path\To\DelphiCompileGate\Run
Run\
|-- Input\ strict Protocol-2 manifests: <job_id>.job.json
|-- Output\ authenticated plugin results: <job_id>.json
|-- Processed\ successfully consumed manifests
|-- Failed\ rejected manifests and *.error.txt
|-- Logs\ watcher logs
`-- Projects\ generated wrapper projects and artifacts
Generated job directories below Projects are retained for two days by
default. When a new wrapper is created, the Gate deletes up to four stale
wrapper directories recursively, including their DPR/DPK, DPROJ, EXE/BPL, DCU,
and related compiler artifacts. Limiting cleanup to four directories per build
prevents a large backlog from blocking the IDE thread.
Set the retention period before starting Delphi:
$env:DELPHI_COMPILE_GATE_TEMP_MAX_AGE_DAYS="7"The minimum is one day. Cleanup runs only when a new wrapper is created, so old
directories remain until the next compile if the Gate is idle. Processed,
Failed, and Logs do not currently have automatic age-based cleanup.
The watcher accepts only files with the exact .job.json suffix. It moves
manifests with invalid schemas, mismatched identities, or unverifiable evidence
to Failed. Do not create or rename queue manifests manually;
compile_project() is the sole supported producer.
Settings are stored atomically at:
%APPDATA%\DelphiCompileGate\DelphiCompileGate.ini
Only these runtime values are editable:
- Watch interval: 250 to 60000 ms
- Compile-timeout threshold: 60000 to 600000 ms
- Experimental close of completed hidden Protocol-2 modules
Settings edits and a pending watcher start take effect only after OK saves the settings successfully. Cancel discards unsaved edits and a pending start. Stopping an active watcher takes effect immediately as a graceful drain; holding Shift requests the hard-stop path. Queue processing is deferred while the Settings/Status dialog is open and resumes after it closes.
Crossing the timeout threshold marks the job as failed. The Gate still waits fail-closed until the IDE compiler is actually inactive before removing its evidence monitors.
The hidden-module close option is off by default, Delphi-13-only, and
experimental rather than release-accepted. It is authorized only after an
authenticated, policy-compliant result has been published successfully or has
the exact compile_failed failure code. Runtime, dialog, evidence,
malformed-request, timeout, target, artifact, identity, and other failures do
not authorize a close.
For an authorized result, the watcher retains only the canonical path of the
wrapper module that was loaded through hidden OpenModule and never shown. It
reacquires that exact module after four quiet timer turns, calls
IOTAModule.CloseModule(True) once, and verifies absence during the settle
phase. It never uses RemoveProject, CloseFile, saving, or retries. A close
or absence-verification failure disables the experiment for the current IDE
session.
A 1,000-job acceptance run kept compile latency stable and closed every hidden
module, but two DelphiLSP processes still grew to approximately 1.08 GB each.
The IDE language-server cache is not released by IOTAModule.CloseModule.
This is an accepted release limitation; indefinite unattended sessions are not
a supported claim, and users should monitor IDE/LSP memory during large runs.
Before calling the API for the first time, select Start Watch in
Delphi Compile Gate Settings / Status..., then select OK.
fromdelphi_compile_gateimportDelphiCompileGateClientclient=DelphiCompileGateClient(timeout=180)
result=client.compile_project(
source_path=r"C:\Path\To\Example\Example.dpr",
project_path=r"C:\Path\To\Example\Example.dproj",
job_id="example_debug_01",
platform="Win32",
configuration="Debug",
raw_result_path=r"C:\Path\To\BuildEvidence\example_debug_01.json",
)
ifnotresult["success"]:
raiseRuntimeError(result.get("failure_code", "compile failed"))source_path must identify an absolute, canonical, regular, non-reparse-point
.dpr or .dpk file.
project_path is optional. When supplied, it must identify an absolute,
canonical, regular, non-reparse-point .dproj with the same directory and file
stem as source_path. When it is omitted, the Gate creates a managed minimal
.dproj.
The client securely generates an empty job_id. Explicit IDs must match
[a-z0-9][a-z0-9_-]{0,63} and be unique for every run. The client refuses to
overwrite preexisting job, result, quarantine, processed, wrapper, or raw
evidence paths.
The allowed targets are exactly:
Win32/DebugWin32/ReleaseWin64/DebugWin64/Release
The default is Win32 / Debug.
When raw_result_path is supplied, the client atomically preserves the exact
result bytes before parsing JSON or cleaning queue state. The returned Python
object adds the preserved path, size, and SHA-256 under _client_evidence.
This client metadata is not part of the preserved plugin JSON.
Callers use the Python API and do not write this format themselves. The client produces canonical UTF-8 JSON with exactly these top-level fields:
{
"input": {
"main_source": {"path": "<absolute .dpr/.dpk>", "size": 123, "sha256": "<64 lowercase hex>"},
"project": {"path": null, "size": null, "sha256": null}
},
"job_id": "example_01",
"kind": "project_wrapper_build",
"nonce": "<32 lowercase hex>",
"protocol": 2,
"request_hash": "<64 lowercase hex>",
"schema_version": 2,
"target": {"configuration": "Debug", "platform": "Win32"}
}When a .dproj is supplied, input.project contains its absolute path, size,
and hash evidence. The request hash binds the canonical manifest bytes with the
hash field set to zeroes.
The Gate never opens the original project. It creates one unique managed wrapper per job under:
<runtime-base>\Projects\<job_id>\
The wrapper reads the original .dpr or .dpk, rewrites relative in '...'
unit paths to absolute paths, and preserves relevant project options from a
supplied .dproj. Without a .dproj, it creates conventional Win32/Win64 and
Debug/Release settings. The original directory is not modified.
Source-only mode cannot reconstruct project-specific defines, runtime
packages, build events, or custom MSBuild imports. Projects that require these
must provide project_path. Source-only .dpr supports program; .dpk is
generated as a package project.
The Gate accepts qualifying source and project files from any workspace the
local Windows account can read. The local account and the runtime queue are the
trust boundary: any process that can write to Input can request an IDE compile
with that account's access. Keep the runtime directory private to the account
and do not expose it through a shared or broadly writable location.
A supplied .dproj is trusted input. Its imports, targets, and custom build
steps can execute commands under the Delphi process account; the Gate is not a
build sandbox. Use project_path only for projects whose build configuration
you trust.
The raw plugin result is an exact Protocol-2 object. The client rejects unknown or missing fields. Its top-level fields are:
schema_version, protocol, job_id, nonce, request_hash, status, success,
failure_code, requested_target, effective_target, input, wrapper, artifact,
identity, compile, interventions, legal_notice
Important interpretation rules:
successis true only withstatus: "ok"andfailure_code: null.compile.errorscontains structured diagnostics for the current job.compile.target_matchedrequires exact agreement among requested, selected, compiler-reported, and effective targets.compile.release_eligibleis true only with complete compile, artifact, identity, file, and intervention evidence. It does not mean that the selected configuration was necessarilyRelease.artifactcontains the path, size, and SHA-256 of the generated.exeor.bpl; these values are nullable on failure.identitybinds the protocol, plugin version, package build, loaded BPL, and Delphi 13 compiler identity.interventionsrecords dialog and policy activity. A policy-approved known technical dialog can makeintervention_freefalse while leavingpolicy_complianttrue.legal_noticealways records consistent Community Edition notice evidence, including whether it was detected and whether it was acknowledged or left open. It always reportsaccepted_terms: false.
A client timeout, quarantined job, or invalid result returns a local
status: "client_failure" value with success: false. This is not an
authenticated plugin result and must not be treated as build evidence.
Protocol 2 starts a narrowly scoped policy worker before the hidden
OpenModule. It uses no keyboard input, focus, clipboard, default button,
Escape, or WM_CLOSE. It posts BM_CLICK only after revalidating an exact,
visible, enabled, policy-approved descendant button.
Dialog text and button fingerprints support both English and German Delphi localizations. Known technical dialogs require a narrow class, text, and button fingerprint. License or EULA terms are never accepted; only an exact localized reject action is permitted, and the result remains ineligible. Unknown dialogs may receive only an exact localized cancel action. Otherwise the dialog is left untouched and the job remains blocked or ineligible.
Delphi 13 uses TProgressForm for both active progress and some terminal build
summaries. The Gate never activates the active-progress Cancel button. It
acknowledges a terminal form only when exactly one visible, enabled actionable
button remains and its normalized text is exactly OK.
Delphi 13 Community Edition can display an informational
TCENotificationDialog during a build. The Gate acknowledges it only when it
is a same-process modal dialog with exactly one visible, enabled OK action
and no acceptance, agreement, or continue control. The result records
classification: "community_edition_usage_notice", the window class, optional
native title, available button, action, and accepted_terms: false. If the
non-windowed VCL body cannot be observed through Win32 text APIs,
text_available is false and text/hash evidence is null. A safely acknowledged
informational notice can remain policy-compliant and release-eligible; it is
never represented as acceptance of license terms.
Compiler diagnostics are captured only during the active Gate compile and are limited to the authenticated wrapper or source scope. Message-service hooks are restored during job cleanup.
The package supports only Delphi 13 Community Edition
(CompilerVersion = 37.0). Both the 32-bit and 64-bit Delphi 13 IDE hosts are
supported and live-tested. Build the design-time BPL for the matching IDE host
architecture; either host can compile Win32 and Win64 project targets. Every
other compiler version fails at package build time. The diagnostic-capture VMT
layout is verified only against the Delphi 13 ToolsAPI.pas. Do not mix DCUs,
DCPs, or BPLs from other IDE versions or host architectures.
- The watcher processes an existing
*.job.jsonqueue when it starts. - At most one job starts per timer cycle.
- An existing same-name result is never silently overwritten. The client rejects colliding state before creating a job.
- Invalid or unprocessable manifests move to
Failedso they cannot permanently block the queue. - The queue is deferred while the Settings/Status dialog is open.
The plugin does not process a job
Inspect Run\Logs\watch_YYYYMMDD.log. Confirm that Delphi 13 is running, the
current package is installed, the watcher is active, and the filename ends
exactly in .job.json.
The Python client reports a timeout
Inspect the Settings/Status dialog and visible Delphi dialogs. A modal dialog that cannot be classified safely under the legal or technical policy is deliberately not acknowledged.
Compilation fails even though the source appears valid
Inspect compile.errors, failure_code, target evidence, and the watcher log.
Provide the original .dproj through project_path when the project depends on
project-specific defines, packages, imports, search paths, or build steps.
[compile_project]
|
v
[Input/<job_id>.job.json, Protocol 2]
|
v
[OTA watcher -> managed wrapper -> Delphi 13 IDE compiler]
|
v
[Output/<job_id>.json, authenticated Protocol-2 evidence]
- Public documentation describes only strict Protocol 2 and Delphi 13 Community Edition.
- Examples use neutral paths and environment variables; no machine-specific or downstream-project paths are required.
- A release must pass the Python contract tests and a Delphi 13 package build.
- Published artifacts must identify plugin version
2.0.0, Protocol2, and build IDdcg-v2-20260904-releaseprep-02. - Security and dialog-policy limitations in
KNOWN_ISSUES.mdmust be reviewed before publishing. - The project is distributed under the MIT License.
DelphiCompileGate is distributed under the MIT License. The plugin does not modify Embarcadero binaries. Users remain responsible for the terms that apply to their Delphi Community Edition installation and projects.