Skip to content

feat(dev): support harness dev and Inspector chat - #68

Closed
Hweinstock wants to merge 12 commits into
refactorfrom
feat/harness-dev-2
Closed

Hweinstock wants to merge 12 commits into
refactorfrom
feat/harness-dev-2

Conversation

@Hweinstock

@Hweinstock Hweinstock commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Description

agentcore dev supports harnesses: deploy and print invoke guidance by default, or open Agent Inspector with --mode browser. --skip-deploy reuses deployed harnesses.

Solution

  • Add harness dev and Inspector invocation.
  • Reuse harness E2E checks for dev.
  • Share selection, cancellation, and validation helpers.
  • Report unknown Inspector harness stream events.
  • Narrow dev inputs and trim tests.
  • Display JSON tool results.
  • Close collectors after startup output failures.
  • Clarify dev inputs and help.
  • Default Inspector harness qualifiers consistently.
  • Cover Inspector stream, error, and runtime startup paths.
  • Preserve existing harness transcript behavior.

Related Issue

Related to aws#1376 (closed) and prior work aws#2525.

Documentation PR

Concise README guidance; command reference generated on release.

Type of Change

  • New feature

Testing

  • 4,113 unit tests passed; 0 failed.
  • Typecheck, lint, format, secrets scan, audit, Node build, and Linux native build passed.
  • Compiled CLI smoke: help, skip-deploy, selection, flag validation, and SIGTERM cleanup.

Verification

  • Manually verified the Agent Inspector UI in the browser.
  • Local patch coverage: 100% (394/394 executable lines); default and explicit qualifiers verified.
  • Earlier AWS E2E: 15 harness tests and 38 runtime checks passed, including cleanup.

Evidence

image

Recorded during the earlier feature verification. Long deployment waits are hidden; the TUI clip ends after dev prints invoke guidance.

CLI browser mode: deploy, serve Inspector, and invoke the harness through Inspector.

Harness dev CLI browser flow

TUI default headless mode: select dev, deploy, and print invoke guidance.

Harness dev TUI headless flow

CLI VHS tape
Output harness-dev-cli.gif
Output harness-dev-cli.txt

Require agentcore
Require python3
Require npm

Set Shell "bash"
Set FontFamily "DejaVu Sans Mono, Noto Sans Symbols2"
Set FontSize 15
Set Width 1280
Set Height 760
Set Padding 12
Set Framerate 10
Set Theme "Catppuccin Mocha"
Set CursorBlink false
Set TypingSpeed 20ms

Env AGENTCORE_TELEMETRY_DISABLED "1"
Env AWS_REGION "us-east-1"
Env AWS_DEFAULT_REGION "us-east-1"

Hide
Type@0ms `export PS1='> '; unset PROMPT_COMMAND; cd "$HARNESS_DEMO_ROOT"; clear`
Enter
Sleep 200ms
Show

Type `agentcore create --name "$HARNESS_DEMO_NAME" --template empty --skip-git`
Enter
Wait+Screen@5m /Created project/
Wait+Line@10s /^>\s*$/
Sleep 1s

Type `cd "$HARNESS_DEMO_NAME"`
Enter
Wait+Line@5s /^>\s*$/

Type `agentcore add harness --name support --memory '{"mode":"disabled"}' --system-prompt 'Reply with exactly HARNESS_DEV_VERIFIED and no other text.'`
Enter
Wait+Line@30s /^>\s*$/
Sleep 1s

Type "agentcore dev --mode browser"
Enter
Sleep 3s
Hide
Wait+Screen@15m /Agent Inspector running at http:\/\/127[.]0[.]0[.]1:[0-9]+/
Show
Sleep 5s
Hide
Sleep 175s
Show
Ctrl+C
Wait+Line@15s /^>\s*$/

Type `cat "$HARNESS_INSPECTOR_EVIDENCE"`
Enter
Wait+Screen@10s /Inspector harness invocation: HARNESS_DEV_VERIFIED/
Sleep 5s
TUI VHS tape
Output harness-dev-tui-headless.gif
Output harness-dev-tui-headless.txt

Require agentcore
Require python3
Require npm

Set Shell "bash"
Set FontFamily "DejaVu Sans Mono, Noto Sans Symbols2"
Set FontSize 15
Set Width 1280
Set Height 760
Set Padding 12
Set Framerate 10
Set Theme "Catppuccin Mocha"
Set CursorBlink false
Set TypingSpeed 20ms

Env AGENTCORE_TELEMETRY_DISABLED "1"
Env AWS_REGION "us-east-1"
Env AWS_DEFAULT_REGION "us-east-1"

Hide
Type@0ms `export PS1='> '; unset PROMPT_COMMAND; cd "$HARNESS_DEMO_ROOT"; clear`
Enter
Sleep 200ms
Show

Type `agentcore create --name "$HARNESS_DEMO_NAME" --template empty --skip-git`
Enter
Wait+Screen@5m /Created project/
Wait+Line@10s /^>\s*$/
Sleep 1s

Type `cd "$HARNESS_DEMO_NAME"`
Enter
Wait+Line@5s /^>\s*$/

Type `agentcore add harness --name support --memory '{"mode":"disabled"}' --system-prompt 'Reply with exactly HARNESS_DEV_VERIFIED and no other text.'`
Enter
Wait+Line@30s /^>\s*$/
Sleep 1s

Type "agentcore"
Enter
Wait+Screen@30s /type to choose a command/
Type "dev"
Wait+Screen@10s /[❯>] dev/
Sleep 2s
Enter
Sleep 3s
Hide
Wait+Screen@15m /Next step:/
Show
Wait+Line@15s /^>\s*$/
Sleep 3s
Harness AWS E2E log — 15 passed, including cleanup

 RUN  v4.1.11 <worktree>

 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > 'managed_memory' can be added to a project 479ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > 'disabled_memory' can be added to a project 477ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > 'semantic_memory' can be added to a project 475ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > 'custom_prompt' can be added to a project 474ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > dev > deploys all harnesses 224664ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > dev > 'disabled_memory' can be invoked after deployed 2512ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > dev > 'semantic_memory' can be invoked after deployed 3731ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > dev > 'custom_prompt' can be invoked after deployed 3845ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > dev > 'managed_memory' can be invoked after deployed 5562ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > deploy > deploys all harnesses 7789ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > deploy > 'disabled_memory' can be invoked after deployed 3020ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > deploy > 'semantic_memory' can be invoked after deployed 3541ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > deploy > 'custom_prompt' can be invoked after deployed 4055ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > deploy > 'managed_memory' can be invoked after deployed 4111ms
 ✓ e2eTest/project/harness.test.ts > add, dev, deploy, and invoke harnesses > removes all harnesses and deploys the empty project 549814ms

 Test Files  1 passed (1)
      Tests  15 passed (15)
   Start at  16:24:55
   Duration  798.28s (transform 31ms, setup 0ms, import 161ms, tests 798.02s, environment 0ms)

JSON report written to <vitest-report.json>
Earlier runtime AWS E2E log — 38 passed, including cleanup
> AGENTCORE_CLI_PATH="$PWD/dist/bin/agentcore-linux-x64" AWS_REGION=us-east-1 bun run test:e2e -- --tagsFilter="harness || runtime"
Runtime results from the combined AWS E2E run:

 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_minimal' can be added to a project 1317ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_strands' can be added to a project 1332ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'py_strands_container' can be added to a project 1292ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_langchain' can be added to a project 2245ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_ts_strands' can be added to a project 7495ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_ts_vercel' can be added to a project 4193ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'mcp_python_fastmcp' can be added to a project 1048ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'a2a_python_strands' can be added to a project 1538ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agui_python_strands' can be added to a project 1340ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'agent_python_minimal' runs locally 3655ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'agent_ts_strands' runs locally 4488ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'mcp_python_fastmcp' runs locally 492ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'agent_ts_vercel' runs locally 1416ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'agent_python_strands' runs locally 5177ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'agent_python_langchain' runs locally 5736ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'agui_python_strands' runs locally 1133ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'a2a_python_strands' runs locally 1254ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > local invocation > 'py_strands_container' runs locally 18269ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > deploys all runtimes 298693ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_ts_strands' can be invoked after deployed 3739ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_minimal' can be invoked after deployed 5578ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_ts_vercel' can be invoked after deployed 3640ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_langchain' can be invoked after deployed 8297ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_strands' can be invoked after deployed 10606ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'mcp_python_fastmcp' can be invoked after deployed 5501ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'py_strands_container' can be invoked after deployed 12146ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'a2a_python_strands' can be invoked after deployed 11556ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agui_python_strands' can be invoked after deployed 11232ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_minimal' can be removed from the project 487ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_strands' can be removed from the project 473ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'py_strands_container' can be removed from the project 492ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_python_langchain' can be removed from the project 486ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_ts_strands' can be removed from the project 475ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agent_ts_vercel' can be removed from the project 474ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'mcp_python_fastmcp' can be removed from the project 472ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'a2a_python_strands' can be removed from the project 480ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > 'agui_python_strands' can be removed from the project 471ms
 ✓ e2eTest/project/templates.test.ts > add, dev, deploy, invoke for runtime templates > deploys the empty project 198683ms

38 runtime E2E tests passed.
Full run: 54 passed; elapsed 723.34s.

Harness E2E verified commit 81e16038c using the compiled binary. Local paths are redacted; all test results and timings are retained.

Follow-up compiled-binary smoke — skip-deploy and SIGTERM cleanup
> agentcore dev --skip-deploy --json
Next step:
  agentcore invoke

> agentcore dev --skip-deploy --port 8080 --no-traces --json
Error: --port, --no-traces does not apply to harness dev.

> agentcore dev --skip-deploy --mode browser --agent support --ui-port 33133 --json
{"type":"status","message":"Agent Inspector running at http://127.0.0.1:33133"}

> GET /api/status
{"mode": "dev", "agents": [], "harnesses": [{"name": "support"}], "running": [], "errors": []}
> SIGTERM
Shutting down…

PASS: exit 130; Inspector port closed.

Checklist

  • I have read CONTRIBUTING.md.
  • Tests cover the requested behavior.
  • Relevant README guidance is included.
  • No new warnings were introduced by the changes.
  • No dependent changes remain unmerged.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Notes

  • Harness dev deploys the whole project, matching deploy.
  • --agent limits the harnesses shown in Inspector.
  • The existing harness ID-length bug is outside this change.

Comment thread src/handlers/project/dev/index.ts Outdated
io.stderr.write(`${message}\n`);
}

const devFlags = [

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

lets inline these below in the handler.

Comment thread src/handlers/project/dev/index.ts Outdated
{ group: "Runtime Options:" },
),
flag("traces", "disable local OTEL trace collection", z.boolean().default(true), {
group: "Runtime Options:",

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

lets make the group string a constant for both harness and runtime.

Comment thread src/handlers/project/dev/index.ts Outdated
config.io.stderr.write("Shutting down…\n");
controller.abort(new UserCancellationError());
};
if (isHarnessDev(ctx.require(ProjectKey), flags.agent)) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

I think we can simplify the control flow. Lets have a function resolveAgentSelection that returns a { type: 'harness', harnesses: [...]} | { type: 'runtime', runtimes: [...]} to drive this flow. then both flows here shouldn't have to re-derive the agents they need to run on.

Comment thread src/handlers/project/dev/index.ts Outdated
ctx: Context,
flags: DevFlags,
): Promise<void> {
const unsupported =

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

lets define a list of unsupportedFlags and use that to verify. avoid ambiguous variable names like unsupported.

Comment thread src/handlers/project/dev/index.ts Outdated
json,
);
},
const target = flags.target ?? DEFAULT_TARGET_NAME;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

this is deploymentTarget.

Comment thread src/handlers/project/dev/index.ts Outdated
await createDeployProjectHandler(config).handle(ctx, { target, yes: flags.yes }, {});
}
if (flags.mode === "headless") {
if (flags["skip-deploy"] || ctx.require(JsonKey)) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

avoid double nesting conditions. Combine nested ifs when possible to make it more readable.

Comment thread src/handlers/project/dev/index.ts Outdated
: project.spec.harnesses,
},
};
const controller = new AbortController();

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

lets use withUserCancellation Here and update it to handle the additional signal. We can do the same for runtime.

Comment thread src/handlers/project/dev/index.ts Outdated
if (flags.traces && runtimes.some((runtime) => runtime.instrumentation?.enableOtel ?? true)) {
const tracesDirectory = join(project.rootPath, "agentcore", ".cli", "traces", "otlp");
let tracePersistErrorReported = false;
collector = await config.startTraceCollector({

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

there may be some opportunities to break this function up into smaller digestible pieces. the collector logic for example seems like a good candidate.

Comment thread src/handlers/project/dev/index.ts Outdated
controller.abort(new UserCancellationError());
};
if (isHarnessDev(ctx.require(ProjectKey), flags.agent)) {
await runHarnessDev(config, ctx, flags);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

i think we can validate the flags on this level within the if statement. I.e. if runtime flags are passed, fail before calling harness dev, and vice versa for harness only flags.

}
}

async function* transformHarnessSse(

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

is there logic we can re-use from the harness invoke path?

}
}

export function harnessStreamError(event: InvokeHarnessStreamOutput) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

if this function isn't used outside the file, lets not export it.

Comment thread src/handlers/project/dev/index.ts Outdated
async function runHarnessDev(
config: DevProjectHandlerConfig,
ctx: Context,
flags: DevFlags,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

rather than adding a type for dev flags and passing them all down, can we pass them down in an options object?

Comment thread src/handlers/project/dev/index.ts Outdated
}

async function startRuntimeTraceCollector(
config: DevProjectHandlerConfig,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

for any function taking 3+ parameters, have it take a props object with nested fields.

@@ -1,5 +1,12 @@
import { describe, expect, test } from "bun:test";

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

are all these tests necessary? there are most test changes than service code. Then tests only need to ensure we cover the cases outlined in the spec with as few tests as possible (no need to double cover).

Comment thread src/handlers/project/dev/index.ts Outdated
name: "dev",
description: "run the project locally for development",
description:
"test changes made to project resources. For Runtime, this is done with a local server. For Harness, this is an alias for deploy.",

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

lets change this comment to make it more concise, and mention that there is agent inspector as well. Keep the same info, just make it more concise and add the agent inspector bit.

@Hweinstock Hweinstock closed this Oct 9, 2026
@Hweinstock
Hweinstock deleted the feat/harness-dev-2 branch October 9, 2026 16:20
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.

1 participant