Skip to content

feat: add an environment-backed feature flag client wired through the context - #2221

Closed
AlexanderRichey wants to merge 1 commit into
refactorfrom
feat/feature-flags
Closed

feat: add an environment-backed feature flag client wired through the context#2221
AlexanderRichey wants to merge 1 commit into
refactorfrom
feat/feature-flags

Conversation

@AlexanderRichey

Copy link
Copy Markdown
Contributor

Summary

Adds a small feature-flag facility so experimental behavior can ship behind an explicit switch. This is the first commit of #2216, split out on its own so the wiring can land ahead of the imperative deploy that consumes it. The only flag it declares is AGENTCORE_CLI_EXPERIMENTAL_IMPERATIVE_DEPLOY, which nothing reads yet; there is no user-visible behavior change beyond one debug log line.

How it works

  • src/featureFlags/ declares FEATURE_FLAGS (code name → environment variable), the consumer-facing FeatureFlags interface (isEnabled, enabled), and EnvFeatureFlags. The class is constructed with an injected processEnv and never reads process.env itself; values are read once at construction so a flag cannot flip mid-command. The contract is deliberately narrow: a flag is on only when the variable's trimmed value is exactly 1. Any other value (0, true, yes, empty) is off.
  • FeatureFlagsKey joins the other root context keys in src/router/router.tsx; withFeatureFlags pins an instance the same way withGlobalConfigAccessor does. createRootHandler installs it for every command (CLI and TUI), defaulting to an instance with nothing enabled so the existing test call sites need no change. src/index.ts is the one place that passes process.env.
  • withLogging writes a single debug line, experimental feature flags enabled, naming the enabled flags, only when at least one is on, so unflagged runs keep their exact log shape.
  • TestFeatureFlags (exported from src/testing) and a featureFlags option on renderScreen let handler and screen tests turn an experiment on.
  • README gains an "Experimental features" subsection documenting the =1 contract and that flagged features may change or vanish.

Verification

  • bun run lint:check, bun run format:check, bun run typecheck, bun test (2983 tests, 0 failures at this commit), and bun run build all pass.
  • Live: bun run src/index.ts --help works. With AGENTCORE_CLI_EXPERIMENTAL_IMPERATIVE_DEPLOY=1, a harness list --region us-east-1 --json run wrote {"msg":"experimental feature flags enabled","featureFlags":["imperativeDeploy"],…} to ~/.agentcore/logs/output-*.log; with the variable set to 0 or unset, no such line was written and the command still listed harnesses, so the middleware chain is intact.

Reviewer guide

src/featureFlags/env.ts, src/middleware/withFeatureFlags.tsx, src/handlers/index.tsx, src/middleware/withLogging.tsx, src/testing/featureFlags.tsx.

🤖 Generated with Claude Code

https://claude.ai/code/session_014D5SZ5sApMQHrwd87VjDar

… context

Introduces a small feature-flag facility so experimental behavior can ship
behind an explicit switch. The first (and only) flag is
AGENTCORE_CLI_EXPERIMENTAL_IMPERATIVE_DEPLOY, which nothing consumes yet;
the next commit builds the imperative harness deployment on it.

Design:
- src/featureFlags/ declares FEATURE_FLAGS (code name -> env var), the
  consumer-facing FeatureFlags interface, and EnvFeatureFlags, which is
  constructed with an injected processEnv (never process.env directly) and
  reads it once so a flag cannot flip mid-command. The contract is narrow on
  purpose: a flag is on only when the variable's trimmed value is exactly "1".
- FeatureFlagsKey joins the other root context keys; withFeatureFlags pins an
  instance the same way withGlobalConfigAccessor does. createRootHandler
  installs it for every command (CLI and TUI), defaulting to an instance with
  nothing enabled so the ~65 existing test call sites need no change.
  src/index.ts is the one place that passes process.env.
- withLogging writes one debug line naming the enabled flags, only when at
  least one is on, so unflagged runs keep their exact log shape.
- TestFeatureFlags (src/testing/) and a featureFlags option on renderScreen
  let handler and screen tests turn an experiment on.

No behavior changes for users; README gains an "Experimental features"
subsection documenting the =1 contract.

Read first: src/featureFlags/env.ts, src/middleware/withFeatureFlags.tsx,
src/handlers/index.tsx, src/middleware/withLogging.tsx.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014D5SZ5sApMQHrwd87VjDar
@github-actions github-actions Bot added the size/m PR size: M label Sep 4, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added agentcore-harness-reviewing AgentCore Harness review in progress claude-security-reviewing Claude Code /security-review in progress labels Sep 4, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Sep 4, 2026

@agentcore-devx-automation agentcore-devx-automation Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AgentCore Harness Review

Verdict: Looks good

Nice, tightly-scoped bit of plumbing. A few things I checked and liked:

  • Middleware order is correct: withFeatureFlags is registered before withLogging in src/handlers/index.tsx, which matches the intent that withLogging be able to read FeatureFlagsKey off the context.
  • Env read once, at construction (src/featureFlags/env.ts + src/index.ts): the "flag can't flip mid-command" property is enforced by the constructor snapshotting into a Set, and there's a dedicated test for it. Good.
  • Strict "1" contract: table-driven test covers "0", "true", "yes", "on", "", "11", "1.0", plus surrounding whitespace and undefined. The README documents the same contract.
  • Tests use real dependencies: TestFeatureFlags is a proper in-memory implementation of the FeatureFlags interface rather than a jest/bun mock, and the router tests exercise the middleware end-to-end through Router.route(...) with a real leaf handler. No mocking of withLogging internals or ctx shape — good.
  • Screen harness parity: src/testing/renderScreen.tsx threads the same FeatureFlags instance into both the root handler config and the base Context, so screens and handlers see the same source of truth.

Two things worth calling out, neither blocking:

  1. No telemetry for enabled flags. The debug log line ("experimental feature flags enabled") is local-only. Since imperativeDeploy is currently "reserved" and doesn't gate any behavior yet, this is fine to defer, but when the first consumer lands it would be worth attaching featureFlags: FeatureFlag[] to the CommandRunMetricEvent so adoption of experimental paths is measurable, not just greppable in ~/.agentcore/logs/output.
  2. enabled() return type could be readonly FeatureFlag[] since callers only iterate/log it — minor.

Ship it.

@agentcore-devx-automation agentcore-devx-automation Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Sep 4, 2026
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.08%. Comparing base (97d3d9a) to head (113d5bf).
⚠️ Report is 1 commits behind head on refactor.

Additional details and impacted files
@@            Coverage Diff            @@
##           refactor    #2221   +/-   ##
=========================================
  Coverage     97.07%   97.08%           
=========================================
  Files           544      548    +4     
  Lines         37866    37905   +39     
=========================================
+ Hits          36760    36799   +39     
  Misses         1106     1106           

☔ 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.

Comment thread src/featureFlags/env.ts
export class EnvFeatureFlags implements FeatureFlags {
private readonly enabledFlags: ReadonlySet<FeatureFlag>;

constructor(processEnv: Record<string, string | undefined>) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think about leveraging the global config for this? This could allow customers could do something like:

agentcore config experiments.imperativeDeploy true

and

agentcore config experiments
[insert JSON here with all experiment settings]

We could still allow an env var override to take precedence too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants