SIGN IN SIGN UP
daytonaio / daytona UNCLAIMED

Daytona is a Secure and Elastic Infrastructure for Running AI-Generated Code

0 0 91 TypeScript

feat(guides): add Claude Managed Agents on Daytona guide (#4748)

* feat(guides): add Claude Managed Agents on Daytona guide

Reference implementation and guide for running Claude Managed Agents
inside Daytona sandboxes as a self-hosted environment. Includes polling
and webhook orchestrators, in-sandbox runner, default and minimal
Dockerfiles, snapshot builder, and agent creation helper.

Signed-off-by: rovle <lovre.pesut@gmail.com>

* docs(cma-guide): fix snapshot name in builder example

The inline Daytona().snapshot.create example named the snapshot
daytona-env-default, but the rest of the guide and the orchestrator
both reference byoc-env-default. Align the example.

Signed-off-by: rovle <lovre.pesut@gmail.com>

* fix(cma-guide): ack webhook before draining work

Awaiting drain_work() inside the webhook handler kept the POST open
while sandboxes were starting, which can take tens of seconds and risks
Anthropic timing out and retrying. Schedule the drain as a FastAPI
BackgroundTasks task instead and return {"status": "queued"} immediately.
DRAIN_LOCK inside drain_work already serializes overlapping drains.

Signed-off-by: rovle <lovre.pesut@gmail.com>

* fix(guides): cap exponent in polling backoff

After enough consecutive transient poll failures, 2.0 ** transient_attempts
would raise OverflowError and kill the poll loop. Cap the exponent at 6;
2**6 already exceeds the existing 60s ceiling, so the backoff shape is
unchanged for normal attempt counts.

Signed-off-by: rovle <lovre.pesut@gmail.com>

* fix(guides): share default snapshot naming between builder and orchestrator

build_default_snapshot.py duplicated the hash-and-prefix logic from
host_lib.default_snapshot_name(), missed the DEFAULT_SNAPSHOT_NAME env
override, and read the Dockerfile cwd-relative instead of repo-anchored.
Either could silently produce a different snapshot than the orchestrator
expects. Call default_snapshot_name() directly so the two paths can't drift.

Signed-off-by: rovle <lovre.pesut@gmail.com>

* fix(guides): fail webhook startup when secret is missing

Previously, a missing ANTHROPIC_WEBHOOK_SECRET only logged a warning;
the orchestrator kept running with healthz reporting OK and every
webhook POST 500'ing. Raise at startup instead so the misconfiguration
surfaces immediately, before the lock is acquired or the janitor starts.

Signed-off-by: rovle <lovre.pesut@gmail.com>

* fix(guides): backstop webhook ack with periodic safety-net drain

A webhook handler that acks before drain_work() runs can lose newly
queued work if the process restarts (deploy, OOM, signal) between the
ack and the background task. Anthropic considers the webhook delivered
and will not redeliver, so the session would never get a runner.

Add a small dedicated thread that calls drain_work() every
WEBHOOK_DRAIN_SECONDS (default 30s). Webhook handler still ack-and-
schedule for low latency on the happy path; the thread catches anything
the background task missed. DRAIN_LOCK already serializes overlapping
drains, so the two paths cannot conflict. Backoff on transient poll
errors mirrors the polling orchestrator.

Adds WEBHOOK_DRAIN_SECONDS and WEBHOOK_RECLAIM_OLDER_THAN_MS env knobs.

Signed-off-by: rovle <lovre.pesut@gmail.com>

* fix(guides): reject non-finite WEBHOOK_DRAIN_SECONDS

float("inf") and float("nan") slipped past the value <= 0 check (NaN
comparisons are always False; inf is > 0), which would then make
shutdown.wait(value) either never return or behave undefined. Require
math.isfinite as well so only finite positive values pass.

Signed-off-by: rovle <lovre.pesut@gmail.com>

---------

Signed-off-by: rovle <lovre.pesut@gmail.com>
L
Lovre Pešut committed
3af0affd1e2764edc505bbd31e8358faff8dacfc
Parent: 4d214df
Committed by GitHub <noreply@github.com> on 5/19/2026, 9:35:44 AM