Files
agentic-dev/.env.example
Danijel Martinek d5c01209ea feat(work): resume implementer session across same-story slices
Wires sandcastle's native `resumeSession` into the dispatch loop so
the implementer walks into task N already knowing what task N-1
discovered — repo layout, helper signatures, gate output, prior diff.
No scratchpad / no hand-curated context file; the agent's own Claude
Code conversation log is the carrier.

Three guardrails keep it bounded:

- Story boundary reset. `currentSession` is dropped whenever
  findNextTask returns a different story id. New domain ≈ new
  context — keeps story 03 from inheriting story 02's residue.
- Token-threshold reset. After each approved slice, sum the
  implementer's last-iteration usage (inputTokens +
  cacheCreationInputTokens + cacheReadInputTokens — caching saves
  dollars but doesn't free window space). If above
  SANDCASTLE_SESSION_TOKEN_RESET (default 140000 ≈ 70% of Sonnet
  4.6's 200k), drop the session before the next task. Configurable
  via env.
- Context-exhausted safety net. If the model rejects with
  "prompt is too long" / "context_length_exceeded" / similar, the
  retry loop drops the session and re-runs the attempt fresh
  exactly once. Doesn't count against SANDCASTLE_MAX_ATTEMPTS
  (different failure mode).

Reviewer always runs fresh — each approve/reject decision should be
independent of prior tasks to keep the gate honest. Within a single
slice's reject-fixup retries, the implementer also carries forward
across attempts (so attempt 2 sees attempt 1's reasoning + the
reviewer notes), but that's per-slice cumulative, not cross-slice.

runOneSlice now returns { sessionId, usage } so executeDispatch can
make the carry-or-reset decision per slice.
2026-05-13 20:13:30 +02:00

102 lines
3.9 KiB
Plaintext

# =============================================================================
# Environment variables — copy this file to .env and fill in your values.
# See docs/guides/runbook.md for the full reference.
# =============================================================================
# --- Required for `pnpm dev` ---
# Postgres connection. Matches `docker compose up -d` default.
DATABASE_URL=postgresql://postgres:postgres@localhost:5433/template
# Payload CMS encryption key. Any random 32+ char string in dev.
PAYLOAD_SECRET=replace-with-a-random-32-char-string
# --- Optional: app URLs (defaults work in dev) ---
NEXT_PUBLIC_APP_URL=http://localhost:3000
CMS_URL=http://localhost:3001
# Force dev-seed binders (mock repos) regardless of NODE_ENV. Useful for
# running pnpm dev without Payload booted.
# USE_DEV_SEED=true
# --- Optional: Sentry observability ---
# Leaving these unset → instrumentation falls back to the no-op tracer/logger.
# Set the DSN for any app you want OTel + Sentry on.
# WEB_NEXT_SENTRY_DSN=
# NEXT_PUBLIC_WEB_NEXT_SENTRY_DSN=
# CMS_SENTRY_DSN=
# WEB_TANSTACK_SENTRY_DSN=
# VITE_WEB_TANSTACK_SENTRY_DSN=
# Source-map upload at build time (production only).
# SENTRY_AUTH_TOKEN=
# SENTRY_ORG=
# SENTRY_PROJECT_WEB_NEXT=
# SENTRY_PROJECT_CMS=
# SENTRY_PROJECT_WEB_TANSTACK=
# OTel trace sample rate (0.0 = none, 1.0 = all). 0.1 recommended in dev.
# SENTRY_TRACES_SAMPLE_RATE=0.1
# SENTRY_ENVIRONMENT=development
# --- Optional: git commit SHA for releases ---
# VERCEL_GIT_COMMIT_SHA=
# NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA=
# VITE_GIT_COMMIT_SHA=
# --- Optional: core-audit (only when `gen core-package audit` is scaffolded) ---
# Salt for GDPR pseudonymisation. PRODUCTION MUST set this to a stable secret.
# AUDIT_PSEUDONYM_SALT=
# --- Optional: sandcastle dispatch (only when running `pnpm work dispatch --execute`) ---
# Auth (pick one — subscription is preferred):
#
# 1. Subscription mode (recommended for Pro/Max subscribers):
# Run `claude login` on the host once. Sandcastle bind-mounts ~/.claude/
# into the sandbox so the container's Claude Code CLI uses your session.
# Zero per-task token spend. No env var needed.
#
# 2. API-key mode (fallback when no host creds available):
# ANTHROPIC_API_KEY=
# OPENAI_API_KEY=
# Override the path to host Claude Code creds (default: ~/.claude/)
# SANDCASTLE_CLAUDE_CREDS_DIR=
# GitHub access (optional — for orchestrator-created PRs)
# GITHUB_TOKEN=
# Sandbox provider (default: docker; alternatives: podman, vercel, daytona)
# SANDCASTLE_PROVIDER=docker
# Agent iteration budgets. Sandcastle's `run()` cuts the agent off after N
# iterations (one iteration = one tool-use + response round-trip). The
# repo's defaults are tuned for typical work; bump if an agent gets cut
# mid-commit (you'll see "Reached max iterations" in .sandcastle/logs/).
#
# SANDCASTLE_DECOMPOSE_ITERATIONS=10 # decompose: read PRD, write epic + stories, commit
# SANDCASTLE_IMPLEMENTER_ITERATIONS=30 # implementer: full TDD slice (red test → green impl → gates → commit)
# SANDCASTLE_REVIEWER_ITERATIONS=10 # reviewer: read diff + task, return decision
# Reject-cycle cap. After this many reviewer rejects on the same slice, the
# dispatch loop gives up on that slice and exits 1 with the last rejection
# notes printed. Bump for tricky slices; lower for fast-feedback iteration.
#
# SANDCASTLE_MAX_ATTEMPTS=3
# Session-resume token threshold. The orchestrator passes the prior
# implementer's session ID into the next slice's run() via sandcastle's
# `resumeSession` — the agent walks into task 2 already knowing where
# helpers live, what the prior diff looked like, which gates passed.
# When the prior iteration's total input tokens (input + cacheRead +
# cacheCreation) crosses this threshold the orchestrator drops the
# session and starts the next task fresh, avoiding mid-slice context
# exhaustion. Default 140000 ≈ 70% of Sonnet 4.6's 200k window.
#
# SANDCASTLE_SESSION_TOKEN_RESET=140000