Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/assets/templates/hello-world-python-container/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM public.ecr.aws/docker/library/python:3.12-slim-trixie

RUN pip install --no-cache-dir uv

WORKDIR /app

ENV UV_SYSTEM_PYTHON=1 \
UV_COMPILE_BYTECODE=1 \
UV_NO_PROGRESS=1 \
PYTHONUNBUFFERED=1 \
PATH="/app/.venv/bin:$PATH"

RUN useradd -m -u 1000 bedrock_agentcore

# Install dependencies first so code changes don't invalidate the layer.
COPY pyproject.toml ./
RUN uv sync --no-dev --no-install-project

COPY --chown=bedrock_agentcore:bedrock_agentcore . .
RUN uv sync --no-dev

USER bedrock_agentcore

# AgentCore Runtime service contract port (HTTP mode).
# https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-service-contract.html
EXPOSE 8080

CMD ["python", "main.py"]
27 changes: 27 additions & 0 deletions src/assets/templates/hello-world-python-container/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# hello-world

An AgentCore Runtime agent built with the [Strands](https://strandsagents.com)
SDK. Scaffolded by `agentcore project create`.

## Layout

- `main.py` — the agent: a `BedrockAgentCoreApp` entrypoint that streams
responses from a Strands `Agent`.
- `pyproject.toml` — dependencies, installed with [uv](https://docs.astral.sh/uv/).

## Develop

Run the agent locally from the project root:

```bash
agentcore project dev
```

Environment variables for local development go in `agentcore/.env.local`
(gitignored).

## Deploy

```bash
agentcore project deploy
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Python
__pycache__/
*.py[cod]
*.egg-info/
.venv/
dist/
build/

# Secrets and environment files
.env
.env.*

# Version control
.git/
17 changes: 17 additions & 0 deletions src/assets/templates/hello-world-python-container/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent

app = BedrockAgentCoreApp()
agent = Agent(system_prompt="You are a helpful assistant.")


@app.entrypoint
async def invoke(payload, context):
"""Stream the agent's response to the caller's prompt."""
prompt = payload.get("prompt", "Hello!")
async for event in agent.stream_async(prompt):
yield event


if __name__ == "__main__":
app.run()
19 changes: 19 additions & 0 deletions src/assets/templates/hello-world-python-container/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "hello-world"
version = "0.1.0"
description = "AgentCore Runtime application using the Strands SDK"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"aws-opentelemetry-distro",
"bedrock-agentcore >= 1.9.1",
"botocore[crt] >= 1.35.0",
"strands-agents >= 1.15.0",
]

[tool.hatch.build.targets.wheel]
packages = ["."]
27 changes: 27 additions & 0 deletions src/assets/templates/hello-world-python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# hello-world

An AgentCore Runtime agent built with the [Strands](https://strandsagents.com)
SDK. Scaffolded by `agentcore project create`.

## Layout

- `main.py` — the agent: a `BedrockAgentCoreApp` entrypoint that streams
responses from a Strands `Agent`.
- `pyproject.toml` — dependencies, installed with [uv](https://docs.astral.sh/uv/).

## Develop

Run the agent locally from the project root:

```bash
agentcore project dev
```

Environment variables for local development go in `agentcore/.env.local`
(gitignored).

## Deploy

```bash
agentcore project deploy
```
7 changes: 7 additions & 0 deletions src/assets/templates/shared/env.local.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Environment variables for local development.
# `agentcore dev` loads this file into your agent's process. Values here
# override anything the CLI injects. This file is gitignored — keep secrets
# out of version control, but they are safe here.
#
# Example:
# MY_API_KEY=...
17 changes: 17 additions & 0 deletions src/assets/templates/shared/gitignore.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Local environment (loaded by `agentcore dev`; never commit secrets)
.env.local
.env*.local

# Python
__pycache__/
*.py[cod]
.venv/

# Node
node_modules/

# AgentCore CLI state
agentcore/.cli/

# CDK
agentcore/cdk/cdk.out/
30 changes: 29 additions & 1 deletion src/core/project/__snapshots__/manager.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots

exports[`FsProjectManager.create scaffolds the expected file tree into a fresh directory 1`] = `
exports[`FsProjectManager.create scaffolds the expected file tree for hello-world-python into a fresh directory 1`] = `
[
".gitignore",
"agentcore/.env.local",
"agentcore/agentcore.json",
"agentcore/aws-targets.json",
"agentcore/cdk/.gitignore",
Expand All @@ -15,6 +17,32 @@ exports[`FsProjectManager.create scaffolds the expected file tree into a fresh d
"agentcore/cdk/package.json",
"agentcore/cdk/test/cdk.test.ts",
"agentcore/cdk/tsconfig.json",
"app/hello-world/README.md",
"app/hello-world/main.py",
"app/hello-world/pyproject.toml",
]
`;

exports[`FsProjectManager.create scaffolds the expected file tree for hello-world-python-container into a fresh directory 1`] = `
[
".gitignore",
"agentcore/.env.local",
"agentcore/agentcore.json",
"agentcore/aws-targets.json",
"agentcore/cdk/.gitignore",
"agentcore/cdk/.npmignore",
"agentcore/cdk/.prettierrc",
"agentcore/cdk/README.md",
"agentcore/cdk/bin/cdk.ts",
"agentcore/cdk/cdk.json",
"agentcore/cdk/jest.config.js",
"agentcore/cdk/lib/cdk-stack.ts",
"agentcore/cdk/package.json",
"agentcore/cdk/test/cdk.test.ts",
"agentcore/cdk/tsconfig.json",
"app/hello-world/.dockerignore",
"app/hello-world/Dockerfile",
"app/hello-world/README.md",
"app/hello-world/main.py",
"app/hello-world/pyproject.toml",
]
Expand Down
17 changes: 12 additions & 5 deletions src/core/project/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import type { DirNode, ProjectNode } from "./tree";
import { dir, file } from "./tree";
import type { AssetSource } from "./source";
import { TEMPLATES } from "./templates";
import type { ProjectTemplate } from "../../handlers/project/types";
import {
ProjectSpecSchema,
type ProjectSpec,
type ProjectTemplate,
} from "../../handlers/project/types";

/** Serializes a value as pretty-printed JSON with a trailing newline. */
const json = (value: unknown): string => `${JSON.stringify(value, null, 2)}\n`;
Expand Down Expand Up @@ -41,21 +45,22 @@ async function expandDir(src: AssetSource, assetDir: string): Promise<ProjectNod
}

function renderName(filename: string): string {
const ignore = filename.match(/^(git|npm)ignore\.template$/);
const ignore = filename.match(/^(git|npm|docker)ignore\.template$/);
return ignore ? `.${ignore[1]}ignore` : filename;
}

/**
* Builds the agentcore.json spec by adding the template's resource sections to the shared base.
* The base fields and template sections never overlap so this is a plain spread.
* Parsed through {@link ProjectSpecSchema} so create can never write a file resolve can't read.
*/
function agentcoreSpec(name: string, template: ProjectTemplate): unknown {
return {
export function agentcoreSpec(name: string, template: ProjectTemplate): ProjectSpec {
return ProjectSpecSchema.parse({
name,
version: 1,
managedBy: "CDK",
...TEMPLATES[template].spec,
};
});
}

/**
Expand All @@ -69,10 +74,12 @@ export async function projectTree(
): Promise<ProjectNode> {
const { appDir, assetDir } = TEMPLATES[template];
return dir(".", [
file(".gitignore", () => src.read("templates/shared/gitignore.template")),
dir("agentcore", [
dir("cdk", await expandDir(src, "cdk")),
file("agentcore.json", async () => json(agentcoreSpec(name, template))),
file("aws-targets.json", async () => json([])),
file(".env.local", () => src.read("templates/shared/env.local.template")),
]),
dir("app", [dir(appDir, await expandDir(src, assetDir))]),
]);
Expand Down
Loading
Loading