Skip to content

Commit f5941e2

Browse files
committed
feat(runtime): add read-only control-plane commands
Add CLI-only get and list commands for runtimes, runtime versions, and runtime endpoints with Harness-style pagination, output, injected Core clients, fixtures, and command coverage.
1 parent d4c31b1 commit f5941e2

37 files changed

Lines changed: 1112 additions & 6 deletions

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ responses. `agentcore` wraps all of that behind one ergonomic tool.
2727

2828
## Command surface
2929

30-
Every leaf command runs headless with flags, or opens the matching TUI screen
31-
when invoked bare.
30+
Harness leaves run headless with flags or open the matching TUI screen when invoked bare. Runtime inspection and config commands are headless only; invoking a Runtime command group without a leaf prints help.
3231

3332
```
3433
agentcore # interactive TUI
@@ -49,6 +48,15 @@ agentcore # interactive TUI
4948
│ ├── list
5049
│ ├── update
5150
│ └── delete
51+
├── runtime # inspect deployed AgentCore Runtimes
52+
│ ├── get # fetch a Runtime by id
53+
│ ├── list # list Runtimes (server-side paginated)
54+
│ ├── version
55+
│ │ ├── get # get a specific Runtime version
56+
│ │ └── list # list a Runtime's versions
57+
│ └── endpoint
58+
│ ├── get # get a Runtime endpoint by qualifier
59+
│ └── list # list a Runtime's endpoints
5260
└── config # read/write global config values
5361
```
5462

@@ -84,6 +92,14 @@ agentcore harness invoke --id <harnessId> --session-id <session> --qualifier PRO
8492

8593
# Run a shell command inside the agent runtime
8694
agentcore harness exec --id <harnessId> --command "ls -la" --json
95+
96+
# Inspect deployed Runtimes without project configuration or deployment
97+
agentcore runtime get --id <runtimeId>
98+
agentcore runtime list --max-results 20
99+
agentcore runtime version get --id <runtimeId> --version <version>
100+
agentcore runtime version list --id <runtimeId> --max-results 20
101+
agentcore runtime endpoint get --id <runtimeId> --qualifier DEFAULT
102+
agentcore runtime endpoint list --id <runtimeId> --max-results 20
87103
```
88104

89105
---

src/components/RouterScreen.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe("menu rendering", () => {
1515
const frame = r.lastFrame()!;
1616
expect(frame).toContain("harness");
1717
expect(frame).toContain("manage agentcore harnesses");
18+
expect(frame).not.toContain("runtime");
1819
expect(frame).toContain("config");
1920
expect(frame).toContain("read/write global config values");
2021
r.unmount();

src/components/RouterScreen.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useMemo, useState } from "react";
22
import { Box, Text, useApp, useInput, useStdin } from "ink";
33
import type { Command } from "commander";
44
import { useNavigate } from "react-router";
5-
import { CommandKey } from "../router";
5+
import { CommandKey, isCommandVisibleInTui } from "../router";
66
import { Layout } from "./Layout";
77
import { Divider } from "./ui/divider";
88
import { TextInput } from "./ui/text-input";
@@ -57,7 +57,10 @@ export function RouterScreen({ ctx, path }: RouterScreenProps) {
5757

5858
const command = resolveCommand(ctx.require(CommandKey), path);
5959
const options: Option[] = useMemo(
60-
() => command.commands.map((c) => ({ name: c.name(), description: c.description() })),
60+
() =>
61+
command.commands
62+
.filter(isCommandVisibleInTui)
63+
.map((c) => ({ name: c.name(), description: c.description() })),
6164
[command],
6265
);
6366

src/core/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { BedrockAgentCoreControlClient } from "@aws-sdk/client-bedrock-agentcore
22
import { BedrockAgentCoreClient } from "@aws-sdk/client-bedrock-agentcore";
33
import { IAMClient } from "@aws-sdk/client-iam";
44
import { HarnessClient } from "./harness";
5+
import { RuntimeClient } from "./runtime";
56
import type {
67
AwsClients,
78
ClientConfig,
@@ -29,6 +30,7 @@ export class CoreClient implements AwsClients {
2930

3031
// Feature-scoped sub-clients. Access as e.g. `coreClient.harness.getHarness(...)`.
3132
readonly harness: HarnessClient = new HarnessClient(this);
33+
readonly runtime: RuntimeClient = new RuntimeClient(this);
3234

3335
constructor(
3436
private readonly createControlClient: CreateControlClient,

src/core/runtime.tsx

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import {
2+
GetAgentRuntimeCommand,
3+
GetAgentRuntimeEndpointCommand,
4+
ListAgentRuntimeEndpointsCommand,
5+
ListAgentRuntimesCommand,
6+
ListAgentRuntimeVersionsCommand,
7+
type GetAgentRuntimeEndpointResponse,
8+
type GetAgentRuntimeResponse,
9+
type ListAgentRuntimeEndpointsResponse,
10+
type ListAgentRuntimesResponse,
11+
type ListAgentRuntimeVersionsResponse,
12+
} from "@aws-sdk/client-bedrock-agentcore-control";
13+
import type { CoreRuntimeClient } from "../handlers/runtime/types";
14+
import type { AwsClients, CoreOptions } from "./types";
15+
import { toClientConfig } from "./utils";
16+
17+
export class RuntimeClient implements CoreRuntimeClient {
18+
constructor(private readonly clients: AwsClients) {}
19+
20+
async getRuntime(id: string, options: CoreOptions): Promise<GetAgentRuntimeResponse> {
21+
return this.clients
22+
.control(toClientConfig(options))
23+
.send(new GetAgentRuntimeCommand({ agentRuntimeId: id }));
24+
}
25+
26+
async getRuntimeVersion(
27+
id: string,
28+
version: string,
29+
options: CoreOptions,
30+
): Promise<GetAgentRuntimeResponse> {
31+
return this.clients.control(toClientConfig(options)).send(
32+
new GetAgentRuntimeCommand({
33+
agentRuntimeId: id,
34+
agentRuntimeVersion: version,
35+
}),
36+
);
37+
}
38+
39+
async getRuntimeEndpoint(
40+
id: string,
41+
qualifier: string,
42+
options: CoreOptions,
43+
): Promise<GetAgentRuntimeEndpointResponse> {
44+
return this.clients.control(toClientConfig(options)).send(
45+
new GetAgentRuntimeEndpointCommand({
46+
agentRuntimeId: id,
47+
endpointName: qualifier,
48+
}),
49+
);
50+
}
51+
52+
async listRuntimes(
53+
nextToken: string | undefined,
54+
maxResults: number | undefined,
55+
options: CoreOptions,
56+
): Promise<ListAgentRuntimesResponse> {
57+
return this.clients
58+
.control(toClientConfig(options))
59+
.send(new ListAgentRuntimesCommand({ nextToken, maxResults }));
60+
}
61+
62+
async listRuntimeVersions(
63+
id: string,
64+
nextToken: string | undefined,
65+
maxResults: number | undefined,
66+
options: CoreOptions,
67+
): Promise<ListAgentRuntimeVersionsResponse> {
68+
return this.clients.control(toClientConfig(options)).send(
69+
new ListAgentRuntimeVersionsCommand({
70+
agentRuntimeId: id,
71+
nextToken,
72+
maxResults,
73+
}),
74+
);
75+
}
76+
77+
async listRuntimeEndpoints(
78+
id: string,
79+
nextToken: string | undefined,
80+
maxResults: number | undefined,
81+
options: CoreOptions,
82+
): Promise<ListAgentRuntimeEndpointsResponse> {
83+
return this.clients.control(toClientConfig(options)).send(
84+
new ListAgentRuntimeEndpointsCommand({
85+
agentRuntimeId: id,
86+
nextToken,
87+
maxResults,
88+
}),
89+
);
90+
}
91+
}

src/handlers/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Router } from "../router";
22
import { createHarnessHandler } from "./harness/index.tsx";
3+
import { createRuntimeHandler } from "./runtime/index.tsx";
34
import { DebugKey, EndpointKey, JsonKey, RegionKey } from "./keys.tsx";
45
import { createConfigHandler } from "./config/";
56
import { createProjectHandler } from "./project/index.ts";
@@ -33,6 +34,7 @@ export function createRootHandler(core: Core, config: RootHandlerConfig): Router
3334

3435
// Install sub handlers
3536
root.handler(createHarnessHandler(core, io));
37+
root.handler(createRuntimeHandler(core, io));
3638
root.handler(createConfigHandler(io));
3739
root.handler(createProjectHandler());
3840

src/handlers/root.test.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ describe("createRootHandler", () => {
99
logger: createSilentLogger(),
1010
});
1111
expect(root.name()).toBe("agentcore");
12-
expect(root.children().map((c) => c.name())).toEqual(["harness", "config", "project"]);
12+
expect(root.children().map((c) => c.name())).toEqual([
13+
"harness",
14+
"runtime",
15+
"config",
16+
"project",
17+
]);
1318
});
1419
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/runtime-1234567890",
3+
"agentRuntimeName": "fixture-runtime",
4+
"agentRuntimeId": "runtime-1234567890",
5+
"agentRuntimeVersion": "3",
6+
"createdAt": {
7+
"$date": "2026-07-20T10:00:00.000Z"
8+
},
9+
"lastUpdatedAt": {
10+
"$date": "2026-07-20T11:00:00.000Z"
11+
},
12+
"roleArn": "arn:aws:iam::123456789012:role/fixture-runtime-role",
13+
"networkConfiguration": {
14+
"networkMode": "PUBLIC"
15+
},
16+
"status": "READY",
17+
"lifecycleConfiguration": {
18+
"idleRuntimeSessionTimeout": 900,
19+
"maxLifetime": 28800
20+
},
21+
"failureReason": "none",
22+
"description": "Runtime fixture with complete read fields"
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/runtime-1234567890",
3+
"agentRuntimeName": "fixture-runtime",
4+
"agentRuntimeId": "runtime-1234567890",
5+
"agentRuntimeVersion": "2",
6+
"createdAt": {
7+
"$date": "2026-07-19T10:00:00.000Z"
8+
},
9+
"lastUpdatedAt": {
10+
"$date": "2026-07-19T11:00:00.000Z"
11+
},
12+
"roleArn": "arn:aws:iam::123456789012:role/fixture-runtime-role",
13+
"networkConfiguration": {
14+
"networkMode": "PUBLIC"
15+
},
16+
"status": "READY",
17+
"lifecycleConfiguration": {
18+
"idleRuntimeSessionTimeout": 900,
19+
"maxLifetime": 28800
20+
},
21+
"failureReason": "none",
22+
"description": "Runtime version fixture"
23+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"liveVersion": "2",
3+
"targetVersion": "3",
4+
"agentRuntimeEndpointArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime-endpoint/runtime-1234567890/DEFAULT",
5+
"agentRuntimeArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/runtime-1234567890",
6+
"description": "Default Runtime endpoint",
7+
"status": "UPDATING",
8+
"createdAt": {
9+
"$date": "2026-07-19T12:00:00.000Z"
10+
},
11+
"lastUpdatedAt": {
12+
"$date": "2026-07-20T12:00:00.000Z"
13+
},
14+
"failureReason": "none",
15+
"name": "DEFAULT",
16+
"id": "endpoint-1234567890"
17+
}

0 commit comments

Comments
 (0)