Skip to content

feat(project): container template, .env.local/.gitignore scaffolding, and project resolution - #1880

Open
tejaskash wants to merge 8 commits into
refactorfrom
feat/project-foundation
Open

feat(project): container template, .env.local/.gitignore scaffolding, and project resolution#1880
tejaskash wants to merge 8 commits into
refactorfrom
feat/project-foundation

Conversation

@tejaskash

@tejaskash tejaskash commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

First PR for agentcore project dev. Before we can run anything locally, two things need to exist: a way to create a container-based project, and a way for commands to find the project they're running in. This PR does both.

What changed

Added a hello-world-python-container template. It's the same Strands agent as the existing template, just built as a container instead of a CodeZip. The Dockerfile is static on purpose — no handlebars conditionals like the old CLI had, since our asset pipeline is a plain byte copy.

New projects also get a root .gitignore and an agentcore/.env.local starter file. The dev command will load .env.local in a later PR. These render from *.template assets because npm strips dotfiles when publishing.

While copying the template I found that pyproject.toml points at a README.md we never shipped. That silently worked for CodeZip but breaks the container build (uv sync runs hatchling, hatchling errors on the missing readme). Both templates now ship a README.

FsProjectManager.resolve() is implemented: walk up from cwd looking for agentcore/agentcore.json, same as git looks for .git. The parsed spec is validated loosely, so projects from the current CLI that carry sections we don't read yet (memories, gateways) still resolve. Two failure modes are now distinct: no project found returns undefined (the middleware turns that into NoProjectError with a hint to run project create), while a broken config throws InvalidProjectConfigError with the zod details. The old CLI conflated these — a JSON typo showed up as "no project found".

withProject is now mounted on every project subcommand except create, so handlers just read the project off the context.

Testing

The main test is a round-trip: create a project from each template, resolve it from a nested subdirectory, and check the models match. Plus coverage for the miss/malformed/legacy cases. 554 tests pass.

What's next

This is 1 of 6 planned PRs for dev: dev server core + CodeZip runner, container runner, OTLP collector, the Agent Inspector web server, and finally the project dev handler that wires it together.

@github-actions github-actions Bot added the agentcore-harness-reviewing AgentCore Harness review in progress label Jul 30, 2026
@codecov-commenter

codecov-commenter commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.01%. Comparing base (5849293) to head (3c9ec6c).

Additional details and impacted files
@@             Coverage Diff              @@
##           refactor    #1880      +/-   ##
============================================
+ Coverage     95.98%   96.01%   +0.03%     
============================================
  Files           208      208              
  Lines          9684     9764      +80     
============================================
+ Hits           9295     9375      +80     
  Misses          389      389              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Jul 30, 2026
@tejaskash tejaskash changed the title feat(project): container template, .env.local/.gitignore scaffolding, and project resolution [NOT READY FOR REVIEW] feat(project): container template, .env.local/.gitignore scaffolding, and project resolution Jul 31, 2026
@tejaskash tejaskash changed the title [NOT READY FOR REVIEW] feat(project): container template, .env.local/.gitignore scaffolding, and project resolution feat(project): container template, .env.local/.gitignore scaffolding, and project resolution Jul 31, 2026
Same agent code as the CodeZip template packaged for a Container build:
a static uv-based Dockerfile (no render-time conditionals), a .dockerignore
rendered from dockerignore.template via the existing ignore-file mechanism,
and a Container runtime entry (with dockerfile) in agentcore.json.
Every template now gets a project-root .gitignore (env files, Python/Node
artifacts, CLI state, cdk.out) and a commented agentcore/.env.local that
agentcore dev will load. Both render from shared *.template assets because
npm strips real dotfiles when publishing.
FsProjectManager.resolve now walks up from the given path for the
agentcore/agentcore.json marker, validates the spec against the new
ProjectSpecSchema (loose, so specs carrying sections we don't read yet
still resolve), and returns the widened Project model (rootPath +
runtimes). A missing project resolves to undefined; a present-but-broken
config throws InvalidProjectConfigError instead of masquerading as
'no project'.

withProject now throws a typed NoProjectError and is mounted on every
project subcommand except create, which runs where no project exists yet.
The search root prefers INIT_CWD since package-manager scripts change
process.cwd().
pyproject.toml declares readme = README.md; without the file, uv sync
fails the hatchling build inside the container image. A starter README
is also just better scaffolding.
TemplateSpec.runtimes is now ProjectRuntime[] so template/schema drift is
a compile error and create() returns the spec directly instead of
re-parsing it through zod.
It was a private bare-Error subclass inside FsReadWriteJson (with a TODO
to model it properly). It now extends AgentCoreCLIError alongside the
other typed errors, and FsProjectManager.resolve catches it by type
instead of sniffing error.cause.
NestedProjectError, InvalidProjectConfigError, ProjectFileExistsError,
EmbeddedAssetNotFoundError, InvalidEnvironmentError, and the runtime
invoke errors were defined next to their throw sites. All typed errors
now live in src/errors like the telemetry model expects; the invoke
errors.ts file is gone.
@tejaskash
tejaskash force-pushed the feat/project-foundation branch from 0fd7837 to 3c9ec6c Compare July 31, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants