Skip to content

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

Open
jesseturner21 wants to merge 2 commits into
mainfrom
fix/exec-harness-support-1724
Open

fix(exec): support harness deployments (#1724)#1728
jesseturner21 wants to merge 2 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.


const options: ExecOptions = {
runtimeArn: cliOptions.runtime,
harnessName: cliOptions.harness,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Interactive mode with --harness still opens the picker.

This branch only guards on options.runtimeArn, so agentcore exec --it --harness foo falls through to runExecLoop(options) on line 165 and shows the picker instead of connecting straight to the harness. loadExecContext already understands harnessName — the direct-PTY path just isn't taking it into account.

Suggested fix:

// With --runtime or --harness: skip agent picker, go straight to PTY
if (options.runtimeArn || options.harnessName) {
  requireTTY();
  await runInteractiveShell(options);
  process.exit(0);
}

Worth adding a test asserting that --harness <name> in --it mode goes through runInteractiveShell (or at least does not invoke pickAgent).


// Mutual exclusion: a name-form --runtime and --harness cannot both be set.
if (options.runtimeArn && options.harnessName) {
throw new Error('Cannot specify both --runtime and --harness.');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutual exclusion is bypassed when --runtime is passed as an ARN.

The --runtime <arn> short-circuit on line 53 returns before the mutex check on line 58, so agentcore exec --runtime arn:... --harness foo silently ignores --harness instead of erroring. The existing test only exercises the name form of --runtime.

Two ways to fix:

  1. Move the mutual-exclusion check above the ARN short-circuit (and above the earlier runtimeArn + region short-circuit on line 24 as well):
    if (options.runtimeArn && options.harnessName) {
      throw new Error('Cannot specify both --runtime and --harness.');
    }
    // ...then the ARN short-circuits and name-form resolution
  2. Enforce mutual exclusion at the CLI layer in command.tsx before constructing ExecOptions, so loadExecContext never has to consider the combination.

Either way, please add a regression test for the ARN + --harness case.

@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.61% 14670 / 37035
🔵 Statements 38.87% 15633 / 40214
🔵 Functions 33.67% 2495 / 7408
🔵 Branches 33.16% 9763 / 29435
Generated in workflow #4058 for commit 2dd6a6f by the Vitest Coverage Report Action

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

2 participants