Skip to main content
FTL executes AI coding tasks through an 8-stage workflow that isolates agent execution, generates adversarial tests in parallel, and ensures human oversight before any changes touch your project.

Workflow stages

When you run ftl 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 .env never enters the sandbox — the agent only sees fake values like ftl_shadow_stripe_secret_key_7f8a2b3c.
When the network proxy is enabled (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 ThreadPoolExecutor to execute both tasks concurrently — test generation doesn’t add to wall-clock time.
The agent writes code to /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:
  • Hardcoded shadow values (exact match or ftl_shadow_* pattern)
  • Known credential patterns: Stripe keys, Anthropic keys, AWS access keys, GitHub PATs, etc.
Dangerous operations (advisory only):
  • SQL: DROP TABLE, DROP DATABASE, TRUNCATE, DELETE FROM without WHERE
  • Shell: rm -rf, shred, dd if=, chmod -R 777
When Bedrock Guardrails is configured (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 /workspace against the snapshot. This avoids host-side Python walking through Docker’s VirtioFS layer, which would be slow for large projects.
The diff shows all file-level changes: created, modified, and deleted files with line-by-line context.
8

Approve

You review the diff and decide:
  • a — approve and merge changes to your project
  • r — reject and discard all changes
  • Any other input — ask the LLM a question about the diff (e.g., “does this handle null inputs?”)
Only approved changes touch your real filesystem. The container remains running for follow-up tasks.

Interactive mode

Running ftl without a task argument starts an interactive shell. Follow-up instructions continue the same agent conversation in the same container:
No cold boot between tasks. Dependencies stay cached. Agent history persists in /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:
For full LLM observability, enable Langfuse:
When CloudWatch is configured (cloudwatch_log_group in .ftlconfig), FTL emits structured JSON events for each session stage: