Built for the Swift Concurrency era.
Designed for humans and AI agents together.
Documentation • Quick Start • Detailed Usage Guide • AI-Native • Architecture • Roadmap
Release capabilities: Reliability and streaming and Operational readiness. Requires Swift 6.3; validated with Swift 6.3.2. Alpha.3 adds operation deadlines, graceful draining and transfer observation; see the migration guide.
Server-side Swift has powerful foundations.
But many frameworks still feel shaped by the pre-Concurrency era:
- EventLoop-heavy application code.
- Transport details leaking into user-facing APIs.
- Runtime patterns optimized for frameworks, not products.
- Architecture that AI agents must reverse-engineer from source.
- Macro-first designs where the runtime truth is hard to inspect.
Daylily takes another path:
- Swift Concurrency first.
- Runtime-first architecture.
- AI-native development workflow.
- Explicit contracts over hidden magic.
- Product-oriented developer experience.
Daylily starts small on purpose: a declarative runtime, a NIO-backed HTTP/1.1 server, and an AIDEV contract that lets AI agents understand, use, upgrade, and extend the project without first spelunking through source code.
import Daylily
@main
@DaylilyServer
struct App {
@GET("/hello")
func hello() -> String {
"Daylily ships."
}
}That's it.
Daylily is built so AI agents can safely understand and extend projects.
Instead of forcing AI to infer architecture from source code alone, Daylily exposes:
- architecture contracts;
- API registries;
- runtime guarantees;
- extension playbooks;
- project maps;
- machine-readable metadata.
AI becomes a first-class development participant.
Macros are tools. Runtime truth matters more.
Daylily prioritizes:
- observable runtime state;
- explicit contracts;
- deterministic architecture;
- introspection-friendly systems.
Daylily provides recommended defaults, but applications do not have to surrender their architecture to the framework.
- The runtime DSL is a first-class API, not a fallback for when macros fail.
@DaylilyServerand route macros are convenience syntax over runtime routes.- The
Dependenciesregistry is a default dependency channel, not a required DI container. - Applications may keep their own composition root, capture their own services, or register their own container.
Daylily is designed around modern Swift:
async/await;Sendable;- structured concurrency;
- transport boundaries that stay out of user-facing APIs.
| Area | Status |
|---|---|
| Swift Concurrency-native runtime | Implemented |
| Declarative route DSL | Implemented |
| Macro route/group declarations | MVP |
| Typed path/query/header inputs | Implemented |
Typed JSON body input with @Body |
Implemented |
| Middleware | Implemented |
| Streaming request body | Implemented |
| JSON body and response helpers | Implemented |
| OpenAPI generation | MVP |
| Observability middleware | MVP |
| Transport-free testing helpers | Implemented |
| AIDEV AI handoff system | Implemented |
| Dependencies registry | MVP + keyed runtime |
Macro @Dependency inputs |
Implemented |
| Macro middleware attributes | Implemented |
| Explicit OpenAPI schemas and security schemes | Implemented |
| Streaming responses and SSE | Implemented |
| Optional query/header inputs | Implemented |
| Full Swift schema derivation | Planned |
Client / SwiftUI / Flutter / API Consumer
|
v
Shared DTOs and HTTP contracts
|
v
Daylily Runtime
|
+--> Route metadata --> OpenAPI
|
+--> AIDEV contracts --> AI agents
|
v
Transport layer
The runtime remains the source of truth. Macros lower into runtime routes and metadata; OpenAPI and AI tooling read the same explicit contract instead of guessing from source code.
Daylily's defaults are intentionally replaceable. When the macro shape or a built-in helper does not fit a real application, the runtime API remains the supported path.
Benchmarks are in progress.
The current focus is:
- predictable architecture;
- concurrency correctness;
- developer experience;
- AI collaboration;
- long-term maintainability.
Raw performance benchmarks will be published after the runtime and beta documentation stabilize.
Daylily is evolving toward a Swift cloud development experience, not only a routing library.
Potential ecosystem directions:
- authentication;
- realtime features;
- queues and background jobs;
- deployment tooling;
- AI-assisted architecture workflow;
- fullstack Swift patterns.
Use Daylily as a SwiftPM package:
.package(url: "https://github.com/sinduke/Daylily.git", from: "0.1.0-alpha.4")The latest published prerelease is 0.1.0-alpha.4. Alpha.4 adds per-write deadlines, bounded observer delivery, nullable contracts and a persistent commerce example. Read the alpha.4 migration guide and release readiness for publication and exact-version validation status. The main README may later describe newer APIs.
Add the product to your target:
.product(name: "Daylily", package: "Daylily")For local framework development or examples, run from source.
From the project root:
swift build
swift test
swift run HelloDaylily --check
swift runTo verify Daylily from a fresh external SwiftPM package:
scripts/consumer-smoke-test.sh --mode path
scripts/consumer-smoke-test.sh --mode release --version 0.1.0-alpha.4To start from the recommended minimal app shape:
cp -R templates/minimal-app MyDaylilyApp
cd MyDaylilyApp
swift build
swift test
swift run App --checkTo try the first real API example:
scripts/example-smoke-test.sh --mode path
cd examples/commerce-api
swift run App --check
swift run AppDaylily uses Swift Testing for the formal test target. If swift test reports no such module 'Testing' while xcode-select -p points at Command Line Tools, run it with an Xcode developer directory, for example:
DEVELOPER_DIR=/Applications/Xcode-26.5.0.app/Contents/Developer swift testThe server listens on:
http://127.0.0.1:8080
Try it:
curl http://127.0.0.1:8080/hello
curl http://127.0.0.1:8080/users/42
curl 'http://127.0.0.1:8080/search?term=daylily&page=1'
curl -H 'x-daylily: ships' http://127.0.0.1:8080/headers
curl -X POST --data 'hi' http://127.0.0.1:8080/echo
curl -X PUT --data 'full' http://127.0.0.1:8080/users/42
curl -X PATCH --data 'partial' http://127.0.0.1:8080/users/42
curl -i -X DELETE http://127.0.0.1:8080/users/42
curl -I http://127.0.0.1:8080/health
curl -i -X OPTIONS http://127.0.0.1:8080/health
printf 'abcdef' | curl --http1.1 -H 'Transfer-Encoding: chunked' -H 'Content-Length:' --data-binary @- http://127.0.0.1:8080/upload/count
curl http://127.0.0.1:8080/json/health
curl -X POST -H 'content-type: application/json' --data '{"message":"hi"}' http://127.0.0.1:8080/json/echoThe rest of this README is the detailed usage guide. It keeps the concrete, copy-pasteable examples close to the project entry point.
Dedicated beta docs are also available:
- Documentation hub
- Quick Start
- Capability Matrix
- Release Readiness
- Operational readiness and deployment
- Contract and real AI regression
- Commerce API Example
- Dependencies Usage
- JSON API Example
- Middleware Example
- Testing Example
README sections:
- Current API: runtime routes, typed parameters, JSON, lifecycle, and server configuration.
- Dependencies: app-wide default dependency registry and custom service wiring.
- Runtime Middleware: application, group, and route middleware with one-shot body rules.
- Observability: request ID and request logging middleware.
- Route Metadata: explicit metadata and minimal OpenAPI generation.
- DaylilyTesting: in-memory tests, request builders, and JSON assertions.
- Macro API MVP:
@DaylilyServer, route macros, typed inputs, and macro limits. - AI-Native Development: AIDEV contracts, registries, playbooks, and agent workflow.
The current runtime API looks like this:
import Daylily
struct HealthPayload: Codable, Sendable {
let status: String
}
struct CreateUserInput: Codable, Sendable {
let name: String
}
struct EchoPayload: Codable, Sendable {
let message: String
}
struct EchoResponse: Codable, Sendable {
let echo: String
}
@main
struct HelloDaylily {
static func main() async throws {
let app = Application {
Get("/") {
"Daylily is awake."
}
Get("/hello") {
"Daylily ships."
}
Get("/users/:id") { request in
let id = try request.parameters.require("id", as: Int.self)
return "User \(id)"
}
Get("/search") { request in
let term = try request.query.require("term", as: String.self)
let page = try request.query.get("page", as: Int.self) ?? 1
return "Search \(term) page \(page)"
}
Get("/headers") { request in
try request.headers.require("x-daylily", as: String.self)
}
Get("/json/health") {
JSON(HealthPayload(status: "ok"))
}
Post("/json/echo") { request in
let input = try await request.json(EchoPayload.self)
return JSON(EchoResponse(echo: input.message))
}
Post("/echo") { request in
try await request.body.string(upTo: .kilobytes(64))
}
Put("/users/:id") { request in
let id = try request.parameters.require("id", as: Int.self)
let body = try await request.body.string(upTo: .kilobytes(64))
return "Updated user \(id): \(body)"
}
Patch("/users/:id") { request in
let id = try request.parameters.require("id", as: Int.self)
let body = try await request.body.string(upTo: .kilobytes(64))
return "Patched user \(id): \(body)"
}
Delete("/users/:id") {
Status.noContent
}
Head("/health") {
Status.ok
}
Options("/health") {
Status.noContent
}
}
try await app.run()
}
}Lifecycle hooks are available before ecosystem modules:
let app = Application {
Get("/hello") { "ok" }
}
.configure {
// register configuration
}
.boot {
// open resources
}
.started {
// server has bound successfully
}
.shutdown {
// stop accepting work
}
.cleanup {
// release resources
}Explicit server configuration is available when defaults are not enough:
try await app.run(
configuration: ServerConfiguration(
host: "0.0.0.0",
port: 8080
)
)Swift ServiceLifecycle support lives in the optional DaylilyServiceLifecycle module:
import Daylily
import DaylilyServiceLifecycle
import Logging
import ServiceLifecycle
let serviceGroup = ServiceGroup(
services: [
app.serviceLifecycleService()
],
gracefulShutdownSignals: [.sigint, .sigterm],
logger: Logger(label: "hello-daylily")
)
try await serviceGroup.run()DaylilyServiceLifecycle adapts Application into a ServiceLifecycle Service. It does not replace Daylily lifecycle hooks and is not re-exported by the umbrella Daylily module. The default ServerConfiguration.serviceLifecycleDefault disables Daylily's own signal handling so ServiceGroup owns graceful shutdown signals; pass your own ServerConfiguration if you want a different policy.
Swift HTTP Types support lives in the optional DaylilyHTTPTypes module:
import Daylily
import DaylilyHTTPTypes
let request = Request(
method: HTTPMethod("PROPFIND")!,
path: "/items?tag=tea&tag=oolong"
)
let httpRequest = try request.httpTypesRequest()
let daylilyRequest = Request(httpTypesRequest: httpRequest)DaylilyHTTPTypes converts between Daylily Request/Response values and Swift HTTP Types HTTPRequest/HTTPResponse values. It is not re-exported by the umbrella Daylily module. The adapter preserves custom method tokens, raw request targets, repeated headers, repeated query parameters, and HTTPTypes pseudo fields; conversions that would require lossy header/status legalization throw instead of silently changing values.
Swift OpenAPI Generator server support lives in the optional DaylilyOpenAPITransport module:
import Daylily
import DaylilyOpenAPITransport
import Foundation
let transport = DaylilyOpenAPITransport()
let handler = GeneratedAPIHandler()
try handler.registerHandlers(
on: transport,
serverURL: URL(string: "/api")!
)
try await transport.application().run()DaylilyOpenAPITransport adapts OpenAPIRuntime ServerTransport registrations into Daylily routes. It is not re-exported by the umbrella Daylily module. Whole-segment generated path parameters such as {id} map to Daylily :id parameters; mixed template segments such as {name}.zip throw during registration. Generated response bodies stream by default. Use responseBodyPolicy: .collect(upTo: limit) for explicit bounded buffering.
Daylily includes a small app-wide Dependencies registry for common service wiring:
struct ProductService: Sendable {
func list() async throws -> [Product] {
[]
}
}
let app = Application(dependencies: { dependencies in
dependencies.register(ProductService())
}) {
Get("/products") { request in
let service = try request.dependencies.require(ProductService.self)
return JSON(try await service.list())
}
}The registry supports concrete Sendable values by type:
var dependencies = Dependencies()
dependencies.register(ProductService())
let service = try dependencies.require(ProductService.self)
let optional: ProductService? = dependencies.get()Use typed keys when dependency intent matters more than the concrete type, such as protocol-oriented services or multiple values of the same type:
protocol ProductServing: Sendable {
func list() async throws -> [Product]
}
extension ProductService: ProductServing {}
enum AppDependencies {
static let productService = DependencyKey<any ProductServing>("productService")
static let primaryDatabase = DependencyKey<Database>("database.primary")
static let replicaDatabase = DependencyKey<Database>("database.replica")
}
dependencies.register(ProductService(), for: AppDependencies.productService)
let service = try dependencies.require(AppDependencies.productService)Macro handlers can read keyed dependencies directly with @Dependency:
@GET("/products")
func products(
@Dependency(AppDependencies.productService) service: any ProductServing
) async throws -> JSON<[Product]> {
JSON(try await service.list())
}This is a default tool, not mandatory architecture. Capturing your own services remains equally valid:
let services = MyServices()
let app = Application {
Get("/products") { _ in
try await services.products.list()
}
}For app factories, prefer domain-specific parameters first, then keep a
configureDependencies escape hatch for tests and advanced wiring:
public func makeApplication(productService: ProductService = .live) -> Application {
makeApplication(configureDependencies: { dependencies in
dependencies.register(productService)
})
}
public func makeApplication(
configureDependencies: @Sendable (inout Dependencies) -> Void
) -> Application {
Application(dependencies: configureDependencies) {
Get("/products") { request in
let service = try request.dependencies.require(ProductService.self)
return JSON(try await service.list())
}
}
}Tests can usually override the business service directly:
let client = TestClient(makeApplication(productService: .stub([])))Use Dependencies Usage for the fuller pattern.
Middleware is available at application, group, and route scope:
struct HeaderMiddleware: Middleware {
func handle(_ request: Request, next: Handler) async throws -> Response {
var response = try await next.respond(to: request)
response.headers["x-daylily"] = "ships"
return response
}
}
let app = Application {
Group("/api") {
Get("/health") {
"ok"
}
}
.middleware(HeaderMiddleware())
Get("/hello") {
"Daylily ships."
}
}
.middleware(HeaderMiddleware())Order is:
application -> router dispatch -> group -> route -> handler
Middleware can read request.body, but RequestBody is one-shot. If middleware consumes the body and then calls next, downstream code sees the body as already consumed. Daylily does not perform hidden body replay.
When middleware intentionally needs to inspect body bytes and still pass an equivalent body downstream, use explicit buffering:
struct SignatureMiddleware: Middleware {
func handle(_ request: Request, next: Handler) async throws -> Response {
try await request.withBufferedBody(upTo: .megabytes(1)) { replayed, bytes in
try verify(bytes)
return try await next.respond(to: replayed)
}
}
}The replacement body is still one-shot, and the helper requires an explicit size limit.
DaylilyObservability provides request ID and request logging middleware without adding logging backends or tracing dependencies to DaylilyCore:
let app = Application {
Get("/hello") { request in
request.daylilyRequestID ?? "missing"
}
}
.middleware(RequestIDMiddleware())
.middleware(RequestLoggingMiddleware(sink: ConsoleRequestLogSink()))RequestIDMiddleware always generates a Daylily-owned x-daylily-request-id. Incoming x-request-id is treated as external correlation data, not as Daylily's unique request identity. When no incoming x-request-id exists, Daylily writes its generated request ID to x-request-id for ecosystem compatibility.
RequestLoggingMiddleware records method, path, final status, request ID, external correlation ID, duration, and public error reason. InMemoryRequestLogSink is available for behavior checks and early tests.
SwiftLog support lives in the optional DaylilySwiftLog module:
import Daylily
import DaylilySwiftLog
let app = Application {
Get("/hello") {
"Daylily ships."
}
}
.middleware(
RequestLoggingMiddleware(
sink: SwiftLogRequestLogSink(label: "hello-daylily")
)
)DaylilySwiftLog adapts RequestLog into SwiftLog metadata without replacing RequestLoggingMiddleware. It does not call LoggingSystem.bootstrap(...), and it is not re-exported by the umbrella Daylily module.
Routes can carry runtime metadata without requiring the OpenAPI generator to guess from source code:
let app = Application {
Post("/users") {
Status.created
}
.describe(
summary: "Create user",
tags: ["Users"],
inputs: [
.header("x-daylily", type: "String"),
],
requestBody: .json("CreateUserInput"),
responses: [
.response(.created, contentType: "application/json", type: "UserResponse"),
]
)
}
let document = app.openAPI(title: "Daylily Demo", version: "0.1.0")DaylilyOpenAPI maps route metadata into a minimal OpenAPI document. It converts Daylily path parameters such as /users/:id into OpenAPI paths such as /users/{id}.
The document is Codable, so it can use the existing JSON(...) response wrapper:
let response = JSON(document)This is still an MVP. Deep schema derivation from Swift types is intentionally deferred.
DaylilyTesting provides transport-free test helpers:
import Daylily
import DaylilyTesting
let app = Application {
Get("/hello") {
"Daylily ships."
}
}
let response = try await TestClient(app).get("/hello")
try response.requireStatus(.ok)
try response.requireBody("Daylily ships.")It also includes request builders and JSON assertions:
struct EchoPayload: Codable, Equatable, Sendable {
let message: String
}
struct EchoResponse: Codable, Equatable, Sendable {
let echo: String
}
let request = try TestRequest
.post("/json/echo")
.withJSON(EchoPayload(message: "hi"))
let jsonResponse = try await TestClient(app).send(request)
try jsonResponse.requireStatus(.ok)
try jsonResponse.requireJSON(EchoResponse(echo: "hi"))TestClient calls Application.respond(to:) directly, so tests exercise the same in-memory runtime behavior without opening a socket.
Daylily's macro MVP supports this shape:
import Daylily
struct HealthPayload: Codable, Sendable {
let status: String
}
struct CreateUserInput: Codable, Sendable {
let name: String
}
struct ResponseHeaderMiddleware: Middleware {
let name: String
let value: String
func handle(_ request: Request, next: Handler) async throws -> Response {
var response = try await next.respond(to: request)
response.headers[name] = value
return response
}
}
enum AppMiddleware {
static let observability = ResponseHeaderMiddleware(name: "x-daylily-app", value: "observed")
}
@main
@Use(AppMiddleware.observability)
@DaylilyServer
struct App {
@GET("/hello")
func hello() -> String {
"Daylily ships."
}
@Use(ResponseHeaderMiddleware(name: "x-daylily-route", value: "users"))
@Security("bearerAuth")
@GET("/users/:id")
func user(@Path id: Int) -> String {
"User \(id)"
}
@GET("/accounts/:id")
func account(@Path("id") accountID: Int) -> String {
"Account \(accountID)"
}
@GET("/health")
func health() -> JSON<HealthPayload> {
JSON(HealthPayload(status: "ok"))
}
@POST("/users")
func create(@Body input: CreateUserInput) -> Status {
.created
}
@PUT("/users/:id")
func update(@Path id: Int, req: Request) async throws -> String {
"updated"
}
@PATCH("/users/:id")
func patch(@Path id: Int, req: Request) async throws -> String {
"patched"
}
@DELETE("/users/:id")
func delete(@Path id: Int) -> Status {
.noContent
}
@HEAD("/health")
func head() -> Status {
.ok
}
@OPTIONS("/health")
func options() -> Status {
.noContent
}
@GET("/search")
func search(
@Query term: String,
@Query("page") pageNumber: Int,
@Header("x-daylily") token: String
) -> String {
"\(term):\(pageNumber):\(token)"
}
@Use(ResponseHeaderMiddleware(name: "x-daylily-group", value: "api"))
@GROUP("/api")
struct API {
@GET("/health")
func health() -> String {
"ok"
}
}
}The rule is simple: macros must lower into the runtime route system. The runtime remains the source of truth.
Macro APIs are a default convenience path, not the only supported way to build a Daylily app. If a project needs a custom composition root, non-default initialization, or a handler shape outside the macro MVP, use the runtime DSL directly.
Typed macro inputs also lower into runtime route behavior. @Path, @Query, @Header, and preferred @Body inputs contribute OpenAPI-ready metadata through the same Route.describe(...) model used by handwritten routes. @JSONBody is retained as a compatibility alias spelling for @Body. @Dependency lowers to keyed Request.dependencies.require(...) and does not contribute route metadata.
Macro middleware uses the same runtime middleware model. @Use(...) is supported on the @DaylilyServer type, @GROUP nested structs, and route methods. Its argument is one Swift expression, so named values such as AppMiddleware.observability work without a separate registry.
Security metadata is explicit. @Security("bearerAuth") contributes OpenAPI operation security metadata through Route.describe(security:); it is not inferred from middleware.
Macro apps can define a dependency configuration hook:
func configureDependencies(_ dependencies: inout Dependencies) {
dependencies.register(ProductService(), for: AppDependencies.productService)
}MVP limits:
- handlers must be instance methods;
- the server type must be default-initializable with
Self(); - handlers may use zero parameters, one
Requestparameter,@Path,@Query,@Header,@Dependency, and one@Bodyparameter, with@JSONBodyaccepted as a compatibility alias spelling; @Pathlowers intoreq.parameters.require(_:as:);@Pathnames must match:nameroute segments;- required
@Queryand@Headerlower intorequire(_:as:); optional values lower intoget(_:as:)withrequired: falsemetadata; @Bodylowers intotry await req.json(Type.self);@JSONBodyis a compatibility alias spelling with the same lowering;@Dependency(key)lowers intotry req.dependencies.require(key);@Use(middleware)lowers into runtime.middleware(middleware)and can be applied at app, group, or route scope;@Security("scheme")lowers into route security metadata and OpenAPI operation security;- the raw one-shot request body type is
RequestBody; - grouped types must be default-initializable;
- optional query/header inputs support
T?,Optional<T>, andSwift.Optional<T>; optional paths are rejected; - keyless dependency inference and deep OpenAPI schema derivation are future work.
These are macro MVP limits, not runtime limits.
Daylily is designed so an AI agent can become useful quickly.
Instead of asking AI to guess the architecture from scattered source files, the project contains an explicit AIDEV system:
- AIDEV.md: the main AI development entry point.
- ai/aidev/start-here.md: the first file an AI should read.
- ai/aidev/project-map.md: modules, files, and responsibilities.
- ai/aidev/architecture.md: dependency direction and boundary rules.
- ai/aidev/runtime-contracts.md: component inputs, outputs, guarantees, and extension points.
- ai/aidev/api-registry.md: current public API surface.
- ai/aidev/extension-playbooks.md: recipes for adding verbs, JSON, middleware, streaming body, macros, transports, and checks.
- ai/epics: theme-level planning containers.
- ai/tasks: task-level execution records; tasks are the smallest commit/push unit.
- ai/aidev/registry.yml: machine-readable project registry.
- ai/prompts/daylily-agent.md: reusable prompt for future AI agents.
This means a user can ask an AI to:
- explain how Daylily works;
- add a new HTTP verb;
- extend JSON support;
- design middleware;
- implement macros;
- update the public API registry;
- write or update checks;
- validate the project with the known commands.
The AI does not need to rediscover the project from scratch. It starts from the AIDEV contract, makes a scoped change, updates the contract if needed, and runs validation.
Daylily/
├── AIDEV.md
├── DAYLILY_NOTES.md
├── Package.swift
├── README.md
├── README.zh-CN.md
├── docs/
├── Sources/
│ ├── Daylily/
│ ├── DaylilyCore/
│ ├── DaylilyJSON/
│ ├── DaylilyNIO/
│ ├── DaylilyObservability/
│ ├── DaylilyOpenAPI/
│ ├── DaylilyTesting/
│ ├── DaylilyCheckSuite/
│ └── HelloDaylily/
├── Tests/
│ └── DaylilyTests/
└── ai/
├── epics/
├── aidev/
├── prompts/
└── tasks/
The most important invariants:
DaylilyCoremust not depend on NIO.- User-facing APIs must not expose NIO types.
- Runtime APIs come before macro sugar.
swift runshould keep starting the example server.swift testshould keep passing.swift run HelloDaylily --checkshould keep passing.- Public API changes must update AIDEV.
Near-term:
- Harden the optional ecosystem adapter set through consumer feedback.
- Continue OpenAPI schema expansion and security scheme components after the macro/runtime bridge stays stable.
python3 ai/evals/contracts/test_compatibility.py
scripts/contract-regression-test.sh --mode path
python3 scripts/deployment-trial.py --duration 300 --artifacts /tmp/daylily-deploymentThe deployment command requires Docker and a new/empty artifact directory. It runs two Linux replicas behind Caddy with loopback-only host ports, verifies SSE and rolling shutdown, and removes its own resources. See the guide for defaults, commands, evidence, and limits. Actual model-edit trials are opt-in and consume the user's configured Codex account; they are not part of automatic CI.
Daylily is released under the MIT License.
The execution checklist covers persistent commerce, bounded runtime resources, nullable contracts, sustained external Linux deployment and broader AI edits. Current API and ownership semantics: candidate guide. All priorities and integration are verified; see acceptance results.
scripts/persistent-consumer-smoke-test.sh --mode path
python3 scripts/persistent-commerce-smoke-test.py --help
python3 scripts/sustained-deployment-trial.py --duration 3600 --artifacts /new/empty/daylily-business
python3 ai/evals/repeated-changes/run_extended.py --baseline-only --repetitions 1 --output /new/empty/ai-baselinesThe persistent consumer also accepts exact revision/release sources and records resolver pins. The actual database harness requires Docker. CI adds macOS/Linux persistent consumers and a private TLS/database Linux trial; workflow dispatch with business_trial_seconds=3600 supplies the one-hour acceptance run. Ordinary CI uses 60 seconds. Baseline-only AI checks make no model calls. Actual run_extended.py without --baseline-only is opt-in and uses the configured Codex account; published trial evidence records token usage, unknown monetary cost and all repair attempts.