Skip to content

fix(exec): support harness deployments (#1724)#1728

Merged
tejaskash merged 5 commits into
mainfrom
fix/exec-harness-support-1724
Jul 10, 2026
Merged

fix(exec): support harness deployments (#1724)#1728
tejaskash merged 5 commits into
mainfrom
fix/exec-harness-support-1724

Conversation

@jesseturner21

Copy link
Copy Markdown
Contributor

Problem

Fixes #1724. agentcore exec reported "No deployed runtimes found" for harness deployments, while agentcore status and agentcore invoke worked. Deployed resources live in two buckets — resources.runtimes and resources.harnesses — and exec only inspected runtimes.

Root cause

Two layers:

  1. Discovery: loadExecContext (and the ExecScreen picker) only enumerated resources.runtimes, so a harness-only project always hit the "No deployed runtimes found" throw.
  2. Correct target ARN (found during E2E): a harness must be exec'd via its harness ARN, not the underlying agentRuntimeArn. The Yggdrasill data plane's HarnessLinkedRuntimeValidator blocks ExecuteCommand / InvokeAgentRuntimeCommandShell against a harness-linked runtime ARN ("managed by a harness and cannot be invoked directly"), but routes a harness ARN on the /runtimes/{arn}/... path through the harness exec path (ExecuteCommandActivity.invokeHarnessExecuteCommand → LoopyDP). The first attempt resolved to agentRuntimeArn and got rejected by the service; the corrected fix targets harnessState.harnessArn.

Changes

  • loadExecContext (src/cli/commands/exec/action.ts): harness-aware. Considers both buckets; adds --harness <name>; auto-selects a single runtime, else a single harness; errors when both kinds are deployed and no flag is given; resolves harnesses to the harness ARN.
  • ExecScreen (src/cli/tui/screens/exec/ExecScreen.tsx): picker lists harnesses (via harness ARN); empty-state message updated.
  • --harness flag registered on agentcore exec (command.tsx, types.ts); mutual-exclusion with --runtime.
  • Telemetry: added has_harness to exec metrics (command-run.ts schema + all 3 call sites).

Tests

End-to-end validation (real AWS)

Built the tarball (npm run bundle), installed it into a scratch project, agentcore create (harness is the default) + agentcore deploy to a real harness in us-east-1, then exercised exec against the deployed harness. Verbatim output:

$ agentcore status
Harnesses
  execharness: Deployed (v1) (arn:aws:bedrock-agentcore:us-east-1:...:harness/execharness_execharness-v3okdvEDxv)

# Before the ARN fix — resolving to agentRuntimeArn was rejected by the service:
$ agentcore exec "echo hello"
Error: The agent runtime arn:...:runtime/harness_execharness_execharness-ammHHsAwGz is managed by a harness and cannot be invoked directly. Use the InvokeAgentRuntimeCommand API with the relevant harness ID instead.

# After the fix — plain exec auto-selects the harness (by harness ARN):
$ agentcore exec --json "echo hello && uname -m && id -un"
{"success":true,"exitCode":0,"stdout":"hello\naarch64\nroot\n","stderr":""}

# --harness by name:
$ agentcore exec --harness execharness "echo FIXED-byname && pwd"
FIXED-byname
/home

The deployed CloudFormation stack was torn down after validation.

Constraint: Data plane only accepts a harness ARN (not its linked runtime ARN) on the exec/shell path.
Confidence: high
Scope-risk: narrow

agentcore exec reported "No deployed runtimes found" for harness
deployments because loadExecContext only inspected
resources.runtimes, while status and invoke also inspect
resources.harnesses. A harness carries its underlying runtime ARN in
agentRuntimeArn, which is exactly what exec needs to open a shell.

loadExecContext and the ExecScreen picker are now harness-aware: they
consider both buckets, add a --harness flag, auto-select a single
runtime or (failing that) a single harness, and require an explicit
flag when both kinds are deployed.

Constraint: ExecContext only carries { region, runtimeArn }; a harness
  resolves to harnessState.agentRuntimeArn (a full ARN).
Rejected: Reuse resolveHarness from operations/resolve-agent.ts |
  it returns runtimeId, not the full ARN exec needs, and adds a
  getHarness API call exec does not require.
Confidence: high
Scope-risk: narrow
Directive: Keep the runtimes-only auto-select path unchanged so
  existing single-agent exec behavior does not regress.
Not-tested: Live harness with agentRuntimeArn absent from local state
E2E testing against a real harness deployment revealed the initial fix
resolved a harness to its underlying agentRuntimeArn, which the data
plane rejects: HarnessLinkedRuntimeValidator blocks ExecuteCommand and
the WebSocket shell against harness-linked runtimes ("managed by a
harness and cannot be invoked directly"). The service instead routes a
harness ARN on the /runtimes/{arn}/... path through the harness exec
path (ExecuteCommandActivity.invokeHarnessExecuteCommand delegates to
LoopyDP). loadExecContext and ExecScreen now resolve harnesses to
harnessState.harnessArn.

Verified E2E in us-east-1: `agentcore exec` (auto-select), `exec
--harness <name>`, and `exec --json` all run inside the harness
container; passing agentRuntimeArn is rejected by the service.

Constraint: Data plane only accepts a harness ARN (not its linked
  runtime ARN) on the exec/shell path.
Rejected: Resolve harness -> agentRuntimeArn | service returns
  ValidationException, exec never connects.
Confidence: high
Scope-risk: narrow
Directive: Do not "simplify" harness exec to use agentRuntimeArn — the
  service will reject it. The harness ARN is required.
@jesseturner21 jesseturner21 requested a review from a team July 9, 2026 23:15
@github-actions github-actions Bot added size/m PR size: M agentcore-harness-reviewing AgentCore Harness review in progress labels Jul 9, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Package Tarball

aws-agentcore-0.23.0.tgz

How to install

gh release download pr-1728-tarball --repo aws/agentcore-cli --pattern "*.tgz" --dir /tmp/pr-tarball
npm install -g /tmp/pr-tarball/aws-agentcore-0.23.0.tgz

@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 Jul 9, 2026

@agentcore-cli-automation agentcore-cli-automation left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice fix — the harness discovery path is well-structured and the tests cover the important branches. Found two related issues around --harness handling in the command wiring that should be addressed before merging. Both are behavioral (not style), and neither is exercised by the current tests.

Comment thread src/cli/commands/exec/command.tsx
Comment thread src/cli/commands/exec/action.ts Outdated
@github-actions github-actions Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 39.63% 14685 / 37050
🔵 Statements 38.9% 15651 / 40229
🔵 Functions 33.73% 2501 / 7413
🔵 Branches 33.21% 9784 / 29455
Generated in workflow #4068 for commit abfedb5 by the Vitest Coverage Report Action

@tejaskash

tejaskash commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Nit / simplification the tail of loadExecContext can collapse from 4 branches to a count check.

The new no-flag path handles "0 deployed", "both kinds exist", "N harnesses", and "N runtimes" as four separate states, plus the runtimeKeys/harnessKeys bookkeeping up top. But exec only ever wants one ARN — the thing that matters is the count of candidates, not which kind they are. Flattening both maps into one list gets you there:

// No flag: exec needs exactly one target.
const candidates = [
  ...Object.values(runtimes).map(r => r.runtimeArn),
  ...Object.values(harnesses).map(h => h.harnessArn),
].filter(Boolean);

if (candidates.length === 0) {
  throw new Error(`No deployed runtimes or harnesses found in target '${targetName}'.`);
}
if (candidates.length > 1) {
  throw new Error(
    `Target '${targetName}' has multiple deploy targets. Specify one with --runtime <name> or --harness <name>: ` +
      [...Object.keys(runtimes), ...Object.keys(harnesses)].join(', ')
  );
}
return { region, runtimeArn: candidates[0]! };

Same behavior, ~30 lines → ~18. The one thing you give up is kind-specific ambiguity wording ("Multiple harnesses..." vs "Multiple agents..."); the merged message lists all names and both flags, so it's always correct regardless of mix. If the distinct wording is intentional UX, ignore this.

The explicit --harness and --runtime name-lookup branches are worth keeping separate as-is — different map, different ARN field, different not-found text. Merging those would be more indirection than it saves.

…RN paths

Address PR review feedback (#1728):

- Interactive mode: `exec --it --harness <name>` fell through to the agent
  picker because the direct-PTY guard only checked `runtimeArn`. It now takes
  the direct path for either `runtimeArn` or `harnessName`.
- Mutual exclusion: `--runtime <arn> --harness <name>` silently ignored
  `--harness` because both ARN short-circuits returned before the mutex check.
  Hoisted the mutex to the top of loadExecContext so it covers every path.
- Simplification: collapsed the no-flag tail from four kind-specific branches
  to a single candidate-count check; the merged ambiguity message lists all
  names and both flags, so it is correct regardless of the runtime/harness mix.

Tests: added regressions for `--it --harness` skipping the picker, ARN-form
`--runtime` + `--harness` mutex (with and without --region), and updated the
ambiguity-wording assertions for the merged message.

Constraint: data plane only accepts a harness ARN (not its linked runtime ARN) on the exec path
Rejected: enforce mutex at the CLI layer in command.tsx | loadExecContext is the single chokepoint every caller (incl. TUI exit path) routes through
Confidence: high
Scope-risk: narrow
Directive: the no-flag ambiguity message intentionally merges runtime+harness kinds — do not re-split without restoring the kind-specific wording tests
The AgentCore data plane (InvokeAgentRuntimeCommandShell) explicitly
rejects harness-linked runtimes: interactive shell is not supported for
harness deployments yet. Previously `agentcore exec --it` against a
harness surfaced an opaque 403 reconnect loop with a misleading "check
IAM permission" message. loadExecContext now detects an interactive
session resolving to a harness ARN and throws up front with actionable
guidance to use one-shot exec, which IS supported.

The guard lives in loadExecContext (the single resolution chokepoint)
so it covers --harness, a harness ARN via --runtime, and the auto-select
/ picker paths uniformly. It keys off the resolved ARN (…:harness/…),
and only fires when options.interactive is set — one-shot exec against a
harness is unaffected.

Verified E2E against a real us-east-1 harness under a PTY: `exec --it`
now prints the guidance and makes no network call; one-shot exec still
runs in the harness container.

Constraint: Service blocks InvokeAgentRuntimeCommandShell for harnesses
  (YggDP HarnessLinkedRuntimeValidator / CommandShellActivity guard).
Rejected: Duplicate the check in command.tsx before requireTTY() |
  would not cover auto-select/picker paths; loadExecContext is the one
  chokepoint that sees the resolved ARN in every case.
Confidence: high
Scope-risk: narrow
Directive: Remove this guard only once the service supports the shell
  API for harness-linked runtimes (the error message says "yet").
@github-actions github-actions Bot added size/m PR size: M and removed size/m PR size: M labels Jul 10, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Jul 10, 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 Jul 10, 2026
--harness now accepts a full harness ARN in addition to a name, matching
--runtime <name|arn>. A name is resolved to the harness ARN from deployed
state; an `arn:` value is used directly (with an `arn:` + --region
short-circuit that skips the config read, mirroring --runtime). A runtime
ARN passed to --harness is rejected with guidance to use --runtime, and a
full-ARN --harness skips the project requirement like --runtime does.

Also corrects the stale ExecOptions.harnessName doc comment (it resolves
to the harness ARN, not the underlying agentRuntimeArn).

Confidence: high
Scope-risk: narrow
@github-actions github-actions Bot added size/m PR size: M and removed size/m PR size: M labels Jul 10, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Jul 10, 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 Jul 10, 2026

@tejaskash tejaskash 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.

LGTM

@tejaskash tejaskash merged commit 9bd8327 into main Jul 10, 2026
32 checks passed
@tejaskash tejaskash deleted the fix/exec-harness-support-1724 branch July 10, 2026 16:07
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.

agentcore exec reports 'No deployed runtimes found' for harness deployments

3 participants