# S3 Files + Lambda + Durable Functions + Strands Agents

Agent skill file for building serverless applications that use Amazon S3 Files with Lambda, durable function orchestration, and Strands AI agents.

## What This Covers

Mounting S3 buckets as local file systems in Lambda functions using S3 Files, orchestrating multi-step workflows with durable functions, and building AI agents with Strands SDK that read and write files through the mount. All deployed with SAM.

## S3 Files CloudFormation

### Resource Types
- `AWS::S3Files::FileSystem` — bridges an S3 bucket to NFS
- `AWS::S3Files::MountTarget` — network endpoint per AZ
- `AWS::S3Files::AccessPoint` — controls POSIX identity for clients

These are new and not in cfn-lint yet. Expect false positive lint errors.

### IAM Role for S3 Files
The trust policy uses `elasticfilesystem.amazonaws.com`, NOT `s3files.amazonaws.com`. S3 Files is built on EFS.

```yaml
AssumeRolePolicyDocument:
  Statement:
    - Principal:
        Service: elasticfilesystem.amazonaws.com
      Action: sts:AssumeRole
      Condition:
        StringEquals:
          aws:SourceAccount: !Ref AWS::AccountId
        ArnLike:
          aws:SourceArn: !Sub 'arn:aws:s3files:${AWS::Region}:${AWS::AccountId}:file-system/*'
```

### Access Point (critical for Lambda)
Lambda needs an access point with `PosixUser` and `CreationPermissions`. Without `CreationPermissions`, the root directory is owned by root and Lambda can't write.

```yaml
S3FilesAccessPoint:
  Type: AWS::S3Files::AccessPoint
  Properties:
    FileSystemId: !GetAtt S3FileSystem.FileSystemId
    PosixUser:
      Uid: '1000'
      Gid: '1000'
    RootDirectory:
      Path: /lambda
      CreationPermissions:
        OwnerUid: '1000'
        OwnerGid: '1000'
        Permissions: '755'
```

Note: EFS uses `CreationInfo`. S3 Files uses `CreationPermissions`. Same concept, different property name.

### S3 Bucket Requirements
- Versioning MUST be enabled
- Without it: "Your bucket must have versioning enabled to create a file system"

### Lambda FileSystemConfigs
- Takes the **access point ARN**, not the file system ARN
- `LocalMountPath` must start with `/mnt/`
- Lambda must be in the same VPC as mount targets
- Add `DependsOn` on mount targets (they take ~5 min to create)

### Lambda IAM Permissions
Use `s3files:` namespace, not `elasticfilesystem:`:
- `s3files:ClientMount`
- `s3files:ClientWrite`
- `s3files:ClientRootAccess`

Resource: the file system ARN (not the access point ARN).

### Sync Latency
- Writes from file system to S3: within minutes (~1 min typical)
- S3 object changes to file system: within seconds
- Not millisecond-level. Account for this if downstream systems need immediate reads.

## Durable Functions (Python)

### Handler Pattern
```python
from aws_durable_execution_sdk_python import durable_execution, durable_step, DurableContext, StepContext
from aws_durable_execution_sdk_python.config import ParallelConfig

@durable_step
def my_step(step_ctx: StepContext, arg1: str):
    # All non-deterministic code goes in steps
    return do_work(arg1)

@durable_execution
def handler(event: dict, context: DurableContext) -> dict:
    result = context.step(my_step(arg1))
    # Use context.invoke() to call other Lambda functions
    # Use context.parallel() for concurrent invocations
```

### Key Rules
- All non-deterministic code MUST be in steps (API calls, file I/O, random, datetime)
- Use `context.invoke()` for calling other Lambda functions (not raw boto3)
- Use `context.parallel()` with `ParallelConfig` for concurrent invocations
- Durable functions need `AutoPublishAlias` and qualified ARN invocation
- Execution timeout > 15 min requires async invocation (can't invoke synchronously)

### SAM Config
```yaml
DurableConfig:
  ExecutionTimeout: 3600
  RetentionPeriodInDays: 7
AutoPublishAlias: live
```

### Async API Gateway
For durable functions with long timeouts, use OpenAPI definition with async invocation:
```yaml
requestParameters:
  integration.request.header.X-Amz-Invocation-Type: "'Event'"
```
Returns 202 immediately. Check results in S3 or via execution history.

## Strands Agents (Python)

### Custom Tools on S3 Files Mount
```python
from strands import Agent, tool
from strands.models import BedrockModel

@tool
def read_file(path: str) -> str:
    """Read a file from the workspace."""
    return (Path(WORKSPACE) / path).read_text()

@tool
def write_file(path: str, content: str) -> str:
    """Write a file to the workspace."""
    (Path(WORKSPACE) / path).write_text(content)
    return f"Written to {path}"

model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0", max_tokens=4096)
agent = Agent(model=model, tools=[read_file, write_file], system_prompt="...")
response = agent("Do the task")
```

### Key Rules
- Use inference profile IDs (e.g., `us.anthropic.claude-sonnet-4-20250514-v1:0`), not direct model IDs
- Lambda IAM needs: `bedrock:InvokeModel`, `bedrock:InvokeModelWithResponseStream`, `bedrock:Converse`, `bedrock:ConverseStream`
- Strands SDK is not compatible with Python 3.14 (ast.NameConstant removed). Use 3.13.
- Tools use standard file I/O on the mount path. No boto3 needed for storage.

## VPC Requirements
- S3 Files requires Lambda in a VPC (same as mount targets)
- NAT gateway needed for outbound internet (Bedrock API, GitHub)
- Security groups: Lambda SG allows all outbound, mount target SG allows NFS (2049) from Lambda SG
- VPC Lambda cold starts are no longer the penalty they used to be

## Pitfalls
- Using `s3files.amazonaws.com` or `s3-files.amazonaws.com` as IAM trust principal (use `elasticfilesystem.amazonaws.com`)
- Using `CreationInfo` instead of `CreationPermissions` on S3 Files access points
- Using file system ARN instead of access point ARN in Lambda FileSystemConfigs
- Using `elasticfilesystem:ClientMount` instead of `s3files:ClientMount` for Lambda IAM
- Forgetting bucket versioning (required for S3 Files)
- Python 3.14 incompatibility with Strands SDK
- Synchronous invocation of durable functions with timeout > 15 min

## Reference
- [S3 Files documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files-getting-started.html)
- [Lambda file system access](https://docs.aws.amazon.com/lambda/latest/dg/configuration-filesystem.html)
- [Durable functions](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html)
- [Strands Agents SDK](https://github.com/strands-agents/sdk-python)
- [Working example repo](https://github.com/singledigit/lambda-s3-files-example)
