Workflow stages
When you runftl code "build login component with Supabase auth", FTL executes the following pipeline:
1
Snapshot
FTL creates a point-in-time snapshot of your project using rsync, respecting
.ftlignore patterns. The snapshot is stored in ~/.ftl/snapshots/<id> and serves as the baseline for diff computation.Snapshots can use S3 as a backend by setting
"snapshot_backend": "s3" in .ftlconfig.2
Boot
FTL boots a Docker container for your project. Containers are persistent — keyed by a hash of your project path — so subsequent tasks reuse the same container with warm dependency caches.On fresh containers, FTL runs the
setup command from .ftlconfig to install dependencies. On warm containers, /workspace is wiped and restored from the snapshot, but everything outside (Python packages in /home/ftl/.local/, Node modules, agent history) persists.FTL pre-warms Node.js by running
claude --version in the background during boot, eliminating the 5-8s cold-start penalty on first use.3
Inject
Shadow credentials replace real API keys inside the container. Your When the network proxy is enabled (
.env never enters the sandbox — the agent only sees fake values like ftl_shadow_stripe_secret_key_7f8a2b3c.pip install -e ".[proxy]"), shadow values are swapped back to real keys at the network layer so live API calls work correctly.4
Agent ∥ Tests
The coding agent runs while adversarial tests generate in parallel. FTL uses The agent writes code to
ThreadPoolExecutor to execute both tasks concurrently — test generation doesn’t add to wall-clock time./workspace inside the container. All API keys it sees are shadow values. Agent output streams line-by-line to your terminal.5
Run tests
Pre-generated tests execute the moment the agent finishes. Tests run inside the same sandbox with the same shadow credentials, validating the agent’s changes against the task description.
Test failures are informational — they don’t block merge, but they help you spot logic errors before reviewing the diff.
6
Lint
FTL scans the diff for credential leaks and dangerous operations before showing you the review prompt.Credential violations:When Bedrock Guardrails is configured (
- Hardcoded shadow values (exact match or
ftl_shadow_*pattern) - Known credential patterns: Stripe keys, Anthropic keys, AWS access keys, GitHub PATs, etc.
- SQL:
DROP TABLE,DROP DATABASE,TRUNCATE,DELETE FROMwithoutWHERE - Shell:
rm -rf,shred,dd if=,chmod -R 777
guardrail_id in .ftlconfig), it replaces local lint and hard-blocks the merge if credentials or PII are detected.7
Diff
FTL computes the diff inside the Linux container by comparing The diff shows all file-level changes: created, modified, and deleted files with line-by-line context.
/workspace against the snapshot. This avoids host-side Python walking through Docker’s VirtioFS layer, which would be slow for large projects.8
Approve
You review the diff and decide:Only approved changes touch your real filesystem. The container remains running for follow-up tasks.
a— approve and merge changes to your projectr— reject and discard all changes- Any other input — ask the LLM a question about the diff (e.g., “does this handle null inputs?”)
Interactive mode
Runningftl without a task argument starts an interactive shell. Follow-up instructions continue the same agent conversation in the same container:
/home/ftl/.claude/.
Container lifecycle
One persistent container per project path, keyed by a hash of the absolute path.
Tracing and observability
FTL prints elapsed time at each stage automatically:cloudwatch_log_group in .ftlconfig), FTL emits structured JSON events for each session stage: