Architecture¶
See how ai-dlc is built: its ownership layers, services, provider boundaries and source packages. Under ADR 0001 it does three jobs: the workflow plugin, machine provisioning and the CI-receipt-gated work lifecycle. Terms defines key words.
ai-dlc runs as a local Python CLI and library. The CLI owns machine enrollment mutation; the MCP facade exposes shared work, doctor, knowledge and documentation services. Project adoption uses Copier, provider adapters isolate vendor-specific operations, and agent skills provide judgment. There is no hosted orchestration service; hangar runs cloud sandboxes.
Boundaries¶
Configuration resolves five ownership layers with provenance:
- A private Git profile owns portable modules, MCP preferences, workflow choices, logical credential requirements and pinned team-source subscriptions. Pin an exact revision before enrolling it on every machine.
- The project repository owns shared project configuration, policy, durable architecture, decisions, and runbooks.
- Each machine binding owns local paths, account selections, and mappings from logical credentials to environment-variable names, plus the person's team roles.
- A password manager, keychain, or process environment owns credential values. ai-dlc never records, prints, or synchronizes those values.
- Codex and Claude user/project configuration owns generated client files; ai-dlc re-renders only entries it owns.
Team-source content is selected from verified local caches and rendered through project ownership checks. Source commits advance only through explicit machine sync activation; session-start remote-ref notices never update content. The teamai adapter reads a supported subset without executing upstream tooling.
Enrollment locks, profile/source caches, and operation journals are local control state, not portable authority. The profile and the project are each synchronized by their own Git repository. Machine bindings, credential stores, and local journals stay on their respective machines.
Portable project data selects role providers and checks and may name required credential environment variables; it never contains their values. Machine data supplies account choices and local paths, while the process environment or native sign-in supplies secrets.
Workflow services manage reviewed work, immutable provider bindings, operation reconciliation and evidence-gated completion. Check services produce receipts. Provider adapters implement versioned contracts. Renderers generate deterministic client configuration. Copier owns template answers, original revisions and three-way updates.
Persistence¶
The repository stores architecture, design rationale, decisions, runbooks and reviewed work. Formal specifications belong exclusively to the specification provider. Tracker priority and status are authoritative. The personal knowledge provider is not a repository mirror. Local operation journals aid retries; remote reconciliation and fresh evidence remain necessary across machines.
Deployment and interfaces¶
Prefer one application with explicit module responsibilities over speculative service decomposition. CLI, MCP, and agent clients share validation where an MCP service is exposed; the CLI alone owns machine enrollment mutation. The local CLI and local MCP are the control plane; cloud execution is hangar's.
Client rendering is frozen to the existing clients for local repositories and
CI (project setup --target local|github-actions); hangar renders cloud
sandboxes at claim time. Hook support is a per-client minimum version
(agents/capabilities.toml), not qualification. External provider failures and
uncertain mutations remain visible. Credentials are environment references,
never template values.
Consumer onboarding is a read-only composition boundary in setup/onboarding.py.
It resolves one explicit existing target, target-owned configuration, optional
explicit enrollment identity, host, shell and client support, and existing
operation owners into an ordered plan. It does not run previews or apply
operations, open a network connection, launch a subprocess, stage adoption or
repair caches. The thin project onboard --root PATH CLI emits that plan and
maps its state to an exit code; it has no apply mode or MCP endpoint.
For a fresh target, adoption precedes root-scoped machine planning because the existing machine owner requires the target configuration. Each apply still needs its separate review, and the existing enrollment, adoption, setup, rendering, readiness and check services retain their own review and evidence boundaries. Project configuration wins over conflicting CLI choices, while omitted enrollment stays unselected for a self-contained project.
Effective-environment reporting is an opt-in boundary under environment/.
The local collector projects selected configuration and observations into a
closed schema before serialization or hashing. Pure schema/identity and comparison
functions do not inspect the host; file access and CLI selection remain separate.
Compound doctor/workspace diagnostics are not collectors because they can execute
health checks or inspect unrelated personal state. Ordinary diagnostics and MCP
doctor retain their existing contracts.
Default reporting executes no commands. Fixed version probes require explicit permission and have bounded output, time and inherited environment. Unknown provenance stays unknown; raw profile, source and ownership hashes cannot be exported merely because they passed local integrity checks.
The configuration identity covers only permitted desired fields, and the observation identity adds known engine, platform, runtime, client and guidance facts. Excluded bytes cannot be distinguished by covert hashes, so incomplete reports remain ineligible for native evidence reuse even when their digests match. Neither identity authenticates a machine or substitutes for behavioral checks and native qualification.
Application services signal outcomes in one of two ways. A failure the service
detected raises an exception derived from ai_dlc.errors.AiDlcError:
RefusedError for an operation refused before any change, UncertainError for
one whose effect must be reconciled. The CLI reports every such failure through
one handler as Error: <message> on stderr with the exception's exit code. MCP
lets it propagate as a tool error.
A completed service call returns a JSON object that satisfies the
service result envelope.
Its status is the canonical outcome string, and the values in
ai_dlc.contracts.FAILURE_STATUSES are the failures. Results that still carry a
boolean verdict key (valid, ready, passed, clean) are authoritative
through that key until they migrate to status.
ai_dlc.contracts.succeeded is the one reader of that envelope; commands that
map a returned result to exit status 1 use it. Bare ValueError remains for
argument validation and is caught by the same CLI handler.
Knowledge ownership stays provider-neutral: private knowledge links durable repository material but does not mirror it. Linked Obsidian portals, additive personal workspaces and explicit local directory mounts are implemented; native application qualification remains separately recorded. Guided tracker discovery supports GitHub Issues with optional Projects and Jira Cloud; live qualification is recorded separately. Plane is shipped but unsupported, and the Linear adapter has been removed.
Tracker capabilities and connection¶
Work start consumes declared lifecycle capabilities through the provider registry. A tracker without an in-progress representation leaves its native ticket unchanged while local branch/work setup advances. A legacy adapter without a capability declaration retains its unverified fallback; a declared operation that fails is a visible error. GitHub Project status and native issue completion are separate facts. Finish gates remain authoritative.
Connection handlers discover service-specific names and identities behind the common setup entry point. Saved plans bind effective runtime settings and authored project/work snapshots, with secrets represented only by local authentication references. Configuration changes and retained-work migration are separate actions. Native MCP access supplies broader service context; it does not substitute for these lifecycle contracts. See the provider contract and GitHub setup guide.
Tracker boundary with hangar¶
hangar owns tracker intake for agent jobs; ai-dlc keeps its tracker adapters for the local work lifecycle only. Both may touch the same ticket, so each concern has one owner:
| Concern | Owner |
|---|---|
| Starting agent work from a ticket (Jira status or label, GitHub label or Projects column, Slack, schedules) | hangar intake |
| Ticket write-back during an agent job (queued, started, needs_input, delivered, failed) | hangar |
| Trust and approval of who may start work | hangar, then Tower |
| A developer's local work record, branch binding and specification artifacts | ai-dlc |
Closing a ticket after merge with CI-receipt evidence (work finish) |
ai-dlc, run locally by a person |
Creating tickets from reviewed local work (work publish) |
ai-dlc |
| Bulk and planning workflows (Projects board setup, tracker migration) | ai-dlc, frozen to bug fixes |
Collision rule. While a hangar job works a ticket, ai-dlc must not move that ticket to in-progress. A repository that also uses hangar intake sets
[work]
tracker_writes = "finish-only"
in ai-dlc.toml (project or base layer only). work start then binds the branch
and reads, but never writes, the ticket; work finish still closes it after the
merged-CI gates. The default, lifecycle, keeps the existing start transition.
Both tools may still comment on a ticket. A finish for a ticket that hangar's
delivery already closed reconciles the closed state instead of failing.
Kept adapters: GitHub Issues, GitHub Projects and Jira Cloud. Plane stays shipped
with supported = false: scaffolding refuses it without --allow-unsupported and
doctor reports it as unsupported and unqualified. The Plane adapter is scheduled
for deletion in the next cleanup unless someone objects by the end of P2. The
Linear adapter is removed; a configuration still selecting it gets a typed refusal
naming supported trackers.
Source layout¶
Location under src/ai_dlc/ |
Responsibility |
|---|---|
cli.py, mcp_server.py, __main__.py |
Public command and MCP entry points |
conformance.py |
Public conformance runner entry point |
setup/ |
Read-only consumer onboarding plans, project adoption, provisioning, readiness and provider connection setup |
work/ |
Work lifecycle, traceability, journals and explicit tracker migration |
environment/ |
Shared bootstrap runtime location and owned shell activation; machine enrollment, pinned profile/team sources, credential references and safe effective-environment reporting/comparison |
harness/ |
Skills, pinned bundles, client rendering, components, hooks and local design capture |
documentation/ |
Catalog checks, impact/evidence review, decision-record checks, scoped project-document access, workspace diagnostics, knowledge notes and their shared frontmatter schema (knowledge_notes.py), and vault links |
providers/ |
Contract-backed external service adapters and isolated provider execution |
verification/ |
Sandbox orchestration and its conformance network proxy (test_proxy.py); harness evaluation moved to flightdeck |
config.py, contracts.py, errors.py, provider_definitions.py |
Shared configuration, provider contracts, the result envelope and the exception base |
files.py, locking.py, toml_edit.py |
Shared filesystem boundaries, locking and comment-preserving TOML edits |
_windows_storage/ |
Private native NTFS handle, identity, account/ACL and publication primitives behind the shared filesystem APIs |
setup/commands.py validates the shared POSIX-string, argv and explicit-shell
command forms before setup and check execution. Windows core storage uses
guarded native handles and per-user locks; Unix paths retain their existing
implementation. harness/windows_render.py applies owned render snapshots with
retained backups and refuses recovery over an intervening edit. Native bootstrap
and desktop or client qualification are separate from this core boundary.
These are internal Python packages, not separate deployable services. Public console entry points remain stable. Internal imports use the responsible package; there is no duplicate tree of compatibility forwarding modules. Application services share contracts; provider details stay inside adapters.
scripts/ holds source bootstrap, repository checks and qualification and
release utilities. scripts/cloud/ holds hosted-agent setup shims that
bootstrap the checkout with the local target; scripts/check_client_pins.py
compares the module catalog's client pins with hangar's harness lock.
The unlocked check_env.sh installer, the Rust crate, the legacy templates/
scaffold, its ai-dlc scaffold command and the root copier.yml have all been
removed. The retired Rust plans remain in git history before tag
docs-prune-2026-10.
project init and project adopt copy the packaged project-templates/,
which must not contain vendored trees or personal machine paths. Do not delete
subprocess entry points or assets merely because imports do not reference them
directly.
Workflow plugin¶
Guidance, hooks and skills reach agents through two paths. ai-dlc agents render
writes them into adopted repositories: the AGENTS.md managed section, hooks that
run the hidden CLI-only ai-dlc hook command (so they require the CLI) and skill
copies. scripts/build_workflow_plugin.py packages the same sources as the
optional Claude Code plugin committed at plugins/ai-dlc-workflow/, the
distribution path for team harnesses and sandboxes.
The build reuses the skill lock and shared guidance, writes per-component
digests to plugin.lock.json, and runs as a drift check inside
scripts/check_generated.py. It also writes the Codex form under
plugins/ai-dlc-workflow/native/codex/ (identical skill bytes, a Codex
hooks.json, an AGENTS.md fragment and a .codex-plugin manifest) and records
per-file digests. scripts/publish_workflow_plugin.py uses those digests to
copy both forms into a team harness directory without overwriting anything it
did not publish.
The plugin hooks run harness/hook_shim.py, a standard-library copy.
It delegates to ai-dlc hook only in adopted repositories with the CLI outside
hangar, and otherwise denies only destructive commands; harness/hooks.py
imports its classifier. This repository dogfoods the plugin rather than
rendered skill copies ([agents] skills = []); adopted repositories keep
rendering both skill trees by default. See the
plugin README.
FDE engagement documents¶
documentation/fde.py owns local engagement generation and stage checks behind
the thin fde CLI group. It reads only the explicit charter and stage landing
pages, and has no provider or private-knowledge connection. See the
FDE runbook for paths, metadata and publication limits.