diff --git a/AGENTS.md b/AGENTS.md index 7e00d502..b9a05f05 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,17 +21,28 @@ src/ Note: CDK L3 constructs are in a separate package `@aws/agentcore-cdk`. +## Global Options + +These options are available on all commands: + +- `-h, --help` - Show help for any command +- `--version` - Print CLI version (root command only) + ## CLI Commands - `create` - Create new AgentCore project -- `add` - Add resources (agent, memory, identity, evaluator, online-eval, target) -- `remove` - Remove resources (agent, memory, identity, evaluator, online-eval, target, all) +- `add` - Add resources (agent, memory, identity, evaluator, online-eval, gateway, gateway-target, policy-engine, + policy) +- `remove` - Remove resources (agent, memory, identity, evaluator, online-eval, gateway, gateway-target, policy-engine, + policy, all) - `deploy` - Deploy infrastructure to AWS - `status` - Check deployment status - `dev` - Local development server (CodeZip: uvicorn with hot-reload; Container: Docker build + run with volume mount) - `invoke` - Invoke agents (local or deployed) - `run eval` - Run on-demand evaluation against agent sessions - `evals history` - View past eval run results +- `fetch access` - Fetch access info for a deployed gateway or agent +- `import` - Import resources from a Bedrock AgentCore Starter Toolkit project - `pause online-eval` - Pause (disable) a deployed online eval config - `resume online-eval` - Resume (enable) a paused online eval config - `logs` - Stream or search agent runtime logs @@ -45,8 +56,7 @@ Note: CDK L3 constructs are in a separate package `@aws/agentcore-cdk`. ### Agent Types -- **Template agents**: Created from framework templates (Strands, LangChain_LangGraph, CrewAI, GoogleADK, OpenAIAgents, - AutoGen) +- **Template agents**: Created from framework templates (Strands, LangChain_LangGraph, GoogleADK, OpenAIAgents) - **BYO agents**: Bring your own code with `agentcore add agent --type byo` - **Imported agents**: Import from Bedrock Agents with `agentcore add agent --type import` @@ -58,10 +68,10 @@ Note: CDK L3 constructs are in a separate package `@aws/agentcore-cdk`. ## Primitives Architecture -All resource types (agent, memory, identity, evaluator, online-eval, gateway, mcp-tool) are modeled as **primitives** -- -self-contained classes in `src/cli/primitives/` that own the full add/remove lifecycle for their resource type. -Resources support config-driven tagging via `agentcore.json` and `mcp.json`, with tags flowing through to deployed -CloudFormation resources. +All resource types (agent, memory, identity, evaluator, online-eval, gateway, gateway-target, policy-engine, policy) are +modeled as **primitives** -- self-contained classes in `src/cli/primitives/` that own the full add/remove lifecycle for +their resource type. Resources support config-driven tagging via `agentcore.json` and `mcp.json`, with tags flowing +through to deployed CloudFormation resources. Each primitive extends `BasePrimitive` and implements: `add()`, `remove()`, `previewRemove()`, `getRemovable()`, `registerCommands()`, and `addScreen()`. @@ -73,8 +83,10 @@ Current primitives: - `CredentialPrimitive` — credential/identity creation, .env management, removal - `EvaluatorPrimitive` — custom evaluator creation/removal with cross-reference validation - `OnlineEvalConfigPrimitive` — online eval config creation/removal -- `GatewayPrimitive` — MCP gateway creation/removal -- `GatewayTargetPrimitive` — MCP tool creation/removal with code generation +- `GatewayPrimitive` — gateway creation/removal +- `GatewayTargetPrimitive` — gateway target creation/removal with code generation +- `PolicyEnginePrimitive` — Cedar policy engine creation/removal +- `PolicyPrimitive` — Cedar policy creation/removal within policy engines Singletons are created in `registry.ts` and wired into CLI commands via `cli.ts`. See `src/cli/AGENTS.md` for details on adding new primitives. diff --git a/src/cli/commands/create/command.tsx b/src/cli/commands/create/command.tsx index 5c0a0b47..7f4b5a1e 100644 --- a/src/cli/commands/create/command.tsx +++ b/src/cli/commands/create/command.tsx @@ -159,14 +159,14 @@ export const registerCreate = (program: Command) => { program .command('create') .description(COMMAND_DESCRIPTIONS.create) - .option('--name ', 'Project name (start with letter, alphanumeric only, max 36 chars) [non-interactive]') + .option('--name ', 'Project name (start with letter, alphanumeric only, max 23 chars) [non-interactive]') .option('--no-agent', 'Skip agent creation [non-interactive]') .option('--defaults', 'Use defaults (Python, Strands, Bedrock, no memory) [non-interactive]') .option('--build ', 'Build type: CodeZip or Container (default: CodeZip) [non-interactive]') .option('--language ', 'Target language (default: Python) [non-interactive]') .option( '--framework ', - 'Agent framework (Strands, LangChain_LangGraph, CrewAI, GoogleADK, OpenAIAgents) [non-interactive]' + 'Agent framework (Strands, LangChain_LangGraph, GoogleADK, OpenAIAgents) [non-interactive]' ) .option('--model-provider ', 'Model provider (Bedrock, Anthropic, OpenAI, Gemini) [non-interactive]') .option('--api-key ', 'API key for non-Bedrock providers [non-interactive]') diff --git a/src/cli/commands/dev/command.tsx b/src/cli/commands/dev/command.tsx index ae2147b8..afd352ca 100644 --- a/src/cli/commands/dev/command.tsx +++ b/src/cli/commands/dev/command.tsx @@ -142,11 +142,11 @@ export const registerDev = (program: Command) => { .option('-i, --invoke ', 'Invoke running dev server (use --agent if multiple) [non-interactive]') .option('-s, --stream', 'Stream response when using --invoke [non-interactive]') .option('-l, --logs', 'Run dev server with logs to stdout [non-interactive]') - .option('--tool ', 'MCP tool name (used with --invoke call-tool)') - .option('--input ', 'MCP tool arguments as JSON (used with --invoke call-tool)') + .option('--tool ', 'MCP tool name (used with --invoke call-tool) [non-interactive]') + .option('--input ', 'MCP tool arguments as JSON (used with --invoke call-tool) [non-interactive]') .option( '-H, --header
', - 'Custom header to forward to the agent (format: "Name: Value", repeatable)', + 'Custom header to forward to the agent (format: "Name: Value", repeatable) [non-interactive]', (val: string, prev: string[]) => [...prev, val], [] as string[] ) diff --git a/src/cli/commands/fetch/command.tsx b/src/cli/commands/fetch/command.tsx index 0805ab80..2634e9f8 100644 --- a/src/cli/commands/fetch/command.tsx +++ b/src/cli/commands/fetch/command.tsx @@ -13,10 +13,10 @@ export const registerFetch = (program: Command) => { fetchCmd .command('access') .description('Fetch access info (URL, token, auth guidance) for a deployed gateway or agent.') - .option('--name ', 'Gateway or agent name') - .option('--type ', 'Resource type: gateway (default) or agent', 'gateway') - .option('--target ', 'Deployment target') - .option('--json', 'Output as JSON') + .option('--name ', 'Gateway or agent name [non-interactive]') + .option('--type ', 'Resource type: gateway (default) or agent [non-interactive]', 'gateway') + .option('--target ', 'Deployment target [non-interactive]') + .option('--json', 'Output as JSON [non-interactive]') .action(async (cliOptions: Record) => { const options = cliOptions as unknown as FetchAccessOptions; requireProject(); diff --git a/src/cli/commands/invoke/command.tsx b/src/cli/commands/invoke/command.tsx index 445b3043..c7f1e303 100644 --- a/src/cli/commands/invoke/command.tsx +++ b/src/cli/commands/invoke/command.tsx @@ -106,7 +106,7 @@ export const registerInvoke = (program: Command) => { .option('--input ', 'MCP tool arguments as JSON (use with --tool) [non-interactive]') .option( '-H, --header
', - 'Custom header to forward to the agent (format: "Name: Value", repeatable)', + 'Custom header to forward to the agent (format: "Name: Value", repeatable) [non-interactive]', (val: string, prev: string[]) => [...prev, val], [] as string[] ) diff --git a/src/cli/commands/status/command.tsx b/src/cli/commands/status/command.tsx index cf3eec66..ce42e889 100644 --- a/src/cli/commands/status/command.tsx +++ b/src/cli/commands/status/command.tsx @@ -56,7 +56,10 @@ export const registerStatus = (program: Command) => { .description(COMMAND_DESCRIPTIONS.status) .option('--agent-runtime-id ', 'Look up a specific agent runtime by ID') .option('--target ', 'Select deployment target') - .option('--type ', 'Filter by resource type (agent, memory, credential, gateway, policy-engine, policy)') + .option( + '--type ', + 'Filter by resource type (agent, memory, credential, gateway, evaluator, online-eval, policy-engine, policy)' + ) .option('--state ', 'Filter by deployment state (deployed, local-only, pending-removal)') .option('--agent ', 'Filter to a specific agent') .option('--json', 'Output as JSON') diff --git a/src/cli/primitives/AgentPrimitive.tsx b/src/cli/primitives/AgentPrimitive.tsx index 07040697..c9c05b82 100644 --- a/src/cli/primitives/AgentPrimitive.tsx +++ b/src/cli/primitives/AgentPrimitive.tsx @@ -75,6 +75,7 @@ export interface AddAgentOptions extends VpcOptions { export class AgentPrimitive extends BasePrimitive { readonly kind = 'agent'; readonly label = 'Agent'; + protected override readonly article = 'an'; readonly primitiveSchema = AgentEnvSpecSchema; /** Local instance to avoid circular dependency with registry. */ @@ -195,14 +196,14 @@ export class AgentPrimitive extends BasePrimitive', 'Agent name (start with letter, alphanumeric only, max 64 chars) [non-interactive]') + .option( + '--name ', + 'Agent name (start with letter, alphanumeric and underscores only, max 48 chars) [non-interactive]' + ) .option('--type ', 'Agent type: create, byo, or import [non-interactive]', 'create') .option('--build ', 'Build type: CodeZip or Container (default: CodeZip) [non-interactive]') .option('--language ', 'Language: Python (create), or Python/TypeScript/Other (BYO) [non-interactive]') - .option( - '--framework ', - 'Framework: Strands, LangChain_LangGraph, CrewAI, GoogleADK, OpenAIAgents [non-interactive]' - ) + .option('--framework ', 'Framework: Strands, LangChain_LangGraph, GoogleADK, OpenAIAgents [non-interactive]') .option('--model-provider ', 'Model provider: Bedrock, Anthropic, OpenAI, Gemini [non-interactive]') .option('--api-key ', 'API key for non-Bedrock providers [non-interactive]') .option('--memory ', 'Memory: none, shortTerm, longAndShortTerm (create path only) [non-interactive]') diff --git a/src/cli/primitives/EvaluatorPrimitive.ts b/src/cli/primitives/EvaluatorPrimitive.ts index 20f49e08..86655b1a 100644 --- a/src/cli/primitives/EvaluatorPrimitive.ts +++ b/src/cli/primitives/EvaluatorPrimitive.ts @@ -124,19 +124,22 @@ export class EvaluatorPrimitive extends BasePrimitive', 'Evaluator name') - .option('--level ', 'Evaluation level: SESSION, TRACE, TOOL_CALL') - .option('--model ', 'Bedrock model ID for LLM-as-a-Judge') + .option('--name ', 'Evaluator name [non-interactive]') + .option('--level ', 'Evaluation level: SESSION, TRACE, TOOL_CALL [non-interactive]') + .option('--model ', 'Bedrock model ID for LLM-as-a-Judge [non-interactive]') .option( '--instructions ', - 'Evaluation prompt instructions (must include level-appropriate placeholders, e.g. {context})' + 'Evaluation prompt instructions (must include level-appropriate placeholders, e.g. {context}) [non-interactive]' + ) + .option( + '--rating-scale ', + `Rating scale preset: ${presetIds.join(', ')} (default: 1-5-quality) [non-interactive]` ) - .option('--rating-scale ', `Rating scale preset: ${presetIds.join(', ')} (default: 1-5-quality)`) .option( '--config ', - 'Path to evaluator config JSON file (overrides --model, --instructions, --rating-scale)' + 'Path to evaluator config JSON file (overrides --model, --instructions, --rating-scale) [non-interactive]' ) - .option('--json', 'Output as JSON') + .option('--json', 'Output as JSON [non-interactive]') .action( async (cliOptions: { name?: string; diff --git a/src/cli/primitives/GatewayPrimitive.ts b/src/cli/primitives/GatewayPrimitive.ts index 545f8dd3..cc6d565a 100644 --- a/src/cli/primitives/GatewayPrimitive.ts +++ b/src/cli/primitives/GatewayPrimitive.ts @@ -158,23 +158,27 @@ export class GatewayPrimitive extends BasePrimitive', 'Gateway name') - .option('--description ', 'Gateway description') - .option('--authorizer-type ', 'Authorizer type: NONE or CUSTOM_JWT') - .option('--discovery-url ', 'OIDC discovery URL (for CUSTOM_JWT)') - .option('--allowed-audience ', 'Comma-separated allowed audiences (for CUSTOM_JWT)') - .option('--allowed-clients ', 'Comma-separated allowed client IDs (for CUSTOM_JWT)') - .option('--allowed-scopes ', 'Comma-separated allowed scopes (for CUSTOM_JWT)') - .option('--custom-claims ', 'Custom claim validations as JSON array (for CUSTOM_JWT)') - .option('--client-id ', 'OAuth client ID for gateway bearer token') - .option('--client-secret ', 'OAuth client secret') - .option('--agents ', 'Comma-separated agent names') - .option('--no-semantic-search', 'Disable semantic search for tool discovery') - .option('--exception-level ', 'Exception verbosity level', 'NONE') - .option('--policy-engine ', 'Policy engine name for Cedar-based authorization') - .option('--policy-engine-mode ', 'Policy engine mode: LOG_ONLY or ENFORCE') - .option('--json', 'Output as JSON') + .description('Add an API gateway that routes requests to agent targets') + .option('--name ', 'Gateway name [non-interactive]') + .option('--description ', 'Gateway description [non-interactive]') + .option('--agents ', 'Comma-separated agent names to expose through this gateway [non-interactive]') + .option('--authorizer-type ', 'Authorizer type: NONE or CUSTOM_JWT [non-interactive]') + .option('--discovery-url ', 'OIDC discovery URL (for CUSTOM_JWT) [non-interactive]') + .option('--allowed-audience ', 'Comma-separated allowed audiences (for CUSTOM_JWT) [non-interactive]') + .option('--allowed-clients ', 'Comma-separated allowed client IDs (for CUSTOM_JWT) [non-interactive]') + .option('--allowed-scopes ', 'Comma-separated allowed scopes (for CUSTOM_JWT) [non-interactive]') + .option('--custom-claims ', 'Custom claim validations as JSON array (for CUSTOM_JWT) [non-interactive]') + .option('--client-id ', 'OAuth client ID for fetching gateway bearer tokens [non-interactive]') + .option('--client-secret ', 'OAuth client secret for fetching gateway bearer tokens [non-interactive]') + .option('--no-semantic-search', 'Disable semantic search for gateway target tool discovery [non-interactive]') + .option( + '--exception-level ', + 'Exception detail level in error responses: NONE, ALL [non-interactive]', + 'NONE' + ) + .option('--policy-engine ', 'Policy engine name for Cedar-based authorization [non-interactive]') + .option('--policy-engine-mode ', 'Policy engine mode: LOG_ONLY or ENFORCE [non-interactive]') + .option('--json', 'Output as JSON [non-interactive]') .action(async (rawOptions: Record) => { const cliOptions = rawOptions as unknown as CLIAddGatewayOptions; try { @@ -238,9 +242,9 @@ export class GatewayPrimitive extends BasePrimitive', 'Name of resource to remove') - .option('--force', 'Skip confirmation prompt') - .option('--json', 'Output as JSON') + .option('--name ', 'Name of resource to remove [non-interactive]') + .option('--force', 'Skip confirmation prompt [non-interactive]') + .option('--json', 'Output as JSON [non-interactive]') .action(async (cliOptions: { name?: string; force?: boolean; json?: boolean }) => { try { if (!findConfigRoot()) { diff --git a/src/cli/primitives/GatewayTargetPrimitive.ts b/src/cli/primitives/GatewayTargetPrimitive.ts index 8e0a6082..aea7052a 100644 --- a/src/cli/primitives/GatewayTargetPrimitive.ts +++ b/src/cli/primitives/GatewayTargetPrimitive.ts @@ -245,35 +245,50 @@ export class GatewayTargetPrimitive extends BasePrimitive', 'Target name') - .option('--description ', 'Target description') + .description('Add a target (API, MCP server, Lambda) to a gateway for tool routing') + .option('--name ', 'Target name [non-interactive]') + .option('--description ', 'Target description [non-interactive]') + .option('--gateway ', 'Gateway to attach this target to [non-interactive]') .option( '--type ', - 'Target type (required): mcp-server, api-gateway, open-api-schema, smithy-model, lambda-function-arn' + 'Target type (required): mcp-server, api-gateway, open-api-schema, smithy-model, lambda-function-arn [non-interactive]' ) - .option('--endpoint ', 'MCP server endpoint URL') - .option('--language ', 'Language: Python, TypeScript, Other') - .option('--gateway ', 'Gateway name') - .option('--host ', 'Compute host: Lambda or AgentCoreRuntime') - .option('--outbound-auth ', 'Outbound auth type: oauth, api-key, or none') - .option('--credential-name ', 'Existing credential name for outbound auth') - .option('--oauth-client-id ', 'OAuth client ID (creates credential inline)') - .option('--oauth-client-secret ', 'OAuth client secret (creates credential inline)') - .option('--oauth-discovery-url ', 'OAuth discovery URL (creates credential inline)') - .option('--oauth-scopes ', 'OAuth scopes, comma-separated') - .option('--rest-api-id ', 'API Gateway REST API ID (required for api-gateway type)') - .option('--stage ', 'API Gateway deployment stage (required for api-gateway type)') - .option('--tool-filter-path ', 'Tool filter path pattern, e.g. /pets/*') - .option('--tool-filter-methods ', 'Comma-separated HTTP methods, e.g. GET,POST') + .option('--endpoint ', 'Server endpoint URL (for mcp-server type) [non-interactive]') + .option('--language ', 'Language of target code: Python, TypeScript, Other [non-interactive]') + .option('--host ', 'Where to run the target: Lambda or AgentCoreRuntime [non-interactive]') + .option('--outbound-auth ', 'Outbound auth type: oauth, api-key, or none [non-interactive]') + .option('--credential-name ', 'Existing credential name for outbound auth [non-interactive]') + .option( + '--oauth-client-id ', + 'OAuth client ID — creates credential inline (for oauth auth) [non-interactive]' + ) + .option( + '--oauth-client-secret ', + 'OAuth client secret — creates credential inline (for oauth auth) [non-interactive]' + ) + .option( + '--oauth-discovery-url ', + 'OAuth discovery URL — creates credential inline (for oauth auth) [non-interactive]' + ) + .option('--oauth-scopes ', 'OAuth scopes, comma-separated (for oauth auth) [non-interactive]') + .option('--rest-api-id ', 'REST API ID (for api-gateway type) [non-interactive]') + .option('--stage ', 'Deployment stage (for api-gateway type) [non-interactive]') + .option('--tool-filter-path ', 'Tool filter path pattern, e.g. /pets/* [non-interactive]') + .option('--tool-filter-methods ', 'Comma-separated HTTP methods, e.g. GET,POST [non-interactive]') .option( '--schema ', - 'Path to schema file (relative to project root) or S3 URI (for open-api-schema / smithy-model)' + 'Schema file path or S3 URI (for open-api-schema / smithy-model type) [non-interactive]' + ) + .option( + '--schema-s3-account ', + 'S3 bucket owner account ID for cross-account access (for schema on S3) [non-interactive]' + ) + .option('--lambda-arn ', 'Lambda function ARN (for lambda-function-arn type) [non-interactive]') + .option( + '--tool-schema-file ', + 'Tool schema JSON file path (for lambda-function-arn type) [non-interactive]' ) - .option('--schema-s3-account ', 'S3 bucket owner account ID (for cross-account access)') - .option('--lambda-arn ', 'Lambda function ARN (required for lambda-function-arn type)') - .option('--tool-schema-file ', 'Path to tool schema JSON file (required for lambda-function-arn type)') - .option('--json', 'Output as JSON') + .option('--json', 'Output as JSON [non-interactive]') .action(async (rawOptions: Record) => { // Commander camelCases --outbound-auth to outboundAuth, but our types use outboundAuthType if (rawOptions.outboundAuth && !rawOptions.outboundAuthType) { @@ -464,9 +479,9 @@ export class GatewayTargetPrimitive extends BasePrimitive', 'Name of resource to remove') - .option('--force', 'Skip confirmation prompt') - .option('--json', 'Output as JSON') + .option('--name ', 'Name of resource to remove [non-interactive]') + .option('--force', 'Skip confirmation prompt [non-interactive]') + .option('--json', 'Output as JSON [non-interactive]') .action(async (cliOptions: { name?: string; force?: boolean; json?: boolean }) => { try { if (!findConfigRoot()) { diff --git a/src/cli/primitives/PolicyEnginePrimitive.ts b/src/cli/primitives/PolicyEnginePrimitive.ts index c061c410..cd5f3431 100644 --- a/src/cli/primitives/PolicyEnginePrimitive.ts +++ b/src/cli/primitives/PolicyEnginePrimitive.ts @@ -205,8 +205,11 @@ export class PolicyEnginePrimitive extends BasePrimitive', 'Policy engine name [non-interactive]') .option('--description ', 'Policy engine description [non-interactive]') .option('--encryption-key-arn ', 'KMS encryption key ARN [non-interactive]') - .option('--attach-to-gateways ', 'Comma-separated gateway names to attach this engine to') - .option('--attach-mode ', 'Enforcement mode for attached gateways: LOG_ONLY or ENFORCE') + .option( + '--attach-to-gateways ', + 'Comma-separated gateway names to attach this engine to [non-interactive]' + ) + .option('--attach-mode ', 'Enforcement mode for attached gateways: LOG_ONLY or ENFORCE [non-interactive]') .option('--json', 'Output as JSON [non-interactive]') .action( async (cliOptions: { diff --git a/src/cli/tui/copy.ts b/src/cli/tui/copy.ts index a3541544..fcc813c0 100644 --- a/src/cli/tui/copy.ts +++ b/src/cli/tui/copy.ts @@ -29,22 +29,22 @@ export const COMMAND_DESCRIPTIONS = { /** Main program description */ program: 'Build and deploy Agentic AI applications on AgentCore', /** Command descriptions */ - add: 'Add resources (agent, evaluator, online-eval, memory, identity, target)', + add: 'Add resources to the project.', create: 'Create a new AgentCore project', deploy: 'Deploy project infrastructure to AWS via CDK.', dev: 'Launch local development server with hot-reload.', - edit: 'Open schema editor.', invoke: 'Invoke a deployed agent endpoint.', logs: 'Stream or search agent runtime logs.', package: 'Package agent artifacts without deploying.', remove: 'Remove resources from project config.', status: 'Show deployed resource details and status.', traces: 'View and download agent traces.', - evals: 'View past eval run results. Also supports --agent-arn.', + evals: 'View past eval run results.', fetch: 'Fetch access info for deployed resources.', pause: 'Pause an online eval config. Supports --arn for configs outside the project.', resume: 'Resume a paused online eval config. Supports --arn for configs outside the project.', run: 'Run on-demand evaluation. Supports --agent-arn for agents outside the project.', + import: 'Import resources from a Bedrock AgentCore Starter Toolkit project.', update: 'Check for and install CLI updates', validate: 'Validate agentcore/ config files.', } as const;