feat(kirocrew): add KiroCrew pack — multi-agent crew gateway on Kiro CLI - #79
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aeb2461dfb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| compatible_profiles: | ||
| - builder | ||
|
|
||
| kirocrew: |
There was a problem hiding this comment.
Add kirocrew to the CloudFormation allowed pack list
Adding this registry entry makes the top-level installer list kirocrew from packs/registry.json, but deploy/cloudformation/template.yaml still restricts PackName to the old set (openclaw through troika). In the normal install.sh --pack kirocrew path, CloudFormation rejects the parameter value before UserData/bootstrap can run, so this new pack is not deployable through the supported installer until the template's AllowedValues is updated.
Useful? React with 👍 / 👎.
| - CDN: the installer URL may be temporarily unavailable" | ||
| } | ||
|
|
||
| if ! sh /tmp/install-kirocrew.sh -- "${KIROCREW_INSTALLER_ARGS[@]}"; then |
There was a problem hiding this comment.
Drop the extra separator when executing the installer
When the installer is downloaded to a file, this literal -- is no longer consumed by sh -s; it becomes $1 for KiroCrew's installer. I checked the upstream cli.sh: it accepts --channel, --version, --cdn, and help, and rejects unknown arguments, so installs fail with an unknown -- before resolving the wheel. Invoke the saved script with just "${KIROCREW_INSTALLER_ARGS[@]}" instead.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aa1e26331d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| REPO_URL="https://github.com/inceptionstack/lowkey.git" | ||
| DOCS_URL="https://github.com/inceptionstack/lowkey/wiki" | ||
| TEMPLATE_RAW_URL="https://raw.githubusercontent.com/inceptionstack/lowkey/main/deploy/cloudformation/template.yaml" | ||
| TEMPLATE_RAW_URL="https://raw.githubusercontent.com/inceptionstack/lowkey/${REPO_BRANCH:-main}/deploy/cloudformation/template.yaml" |
There was a problem hiding this comment.
Build the template URL after resolving the branch
When console deploys are run from a local/feature checkout, this assignment is expanded before REPO_BRANCH is detected later, so ${REPO_BRANCH:-main} has already become main; deploy_console then uploads main's CloudFormation template even while the pack registry and params are coming from the feature branch. That makes branch-only packs like kirocrew fail in the console path because CloudFormation receives a template that does not match the selected branch. Build this URL after branch detection or defer the expansion until download time.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cf5d0926a3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| rm -f /tmp/kirocrew-gateway.service | ||
| sudo systemctl daemon-reload | ||
| sudo systemctl enable kirocrew-gateway.service | ||
| sudo systemctl start kirocrew-gateway.service |
There was a problem hiding this comment.
Guard service start failures before verification
When systemctl start returns non-zero, such as if the gateway exits immediately because authentication/configuration is incomplete or the port is unavailable, set -e aborts the pack before the is-active check and warning below can run. In the default start-gateway=true path this turns a recoverable service-start problem into a failed CloudFormation bootstrap; wrap the start in an if/|| warn path before continuing to verification.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d367a5a4d4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # - If ~/.kiro/env exists → headless mode is configured; banner reflects that. | ||
| # - Otherwise → show the interactive-login reminder. | ||
|
|
||
| PACK_TUI_COMMAND="kirocrew gateway" |
There was a problem hiding this comment.
Use a shell for the KiroCrew SSM session
When the installer creates the Lowkey SSM session document, it uses PACK_TUI_COMMAND as the command to run on connect (ensure_ssm_session_document wraps it in bash --login -c). For KiroCrew this starts the foreground web gateway instead of an interactive agent/shell, so if the systemd service is not already holding the port the SSM session is consumed by a server process; if it is already running, users just hit a port-conflict path before falling back. Since this pack already installs kirocrew-gateway.service, the session command should be a shell or a non-blocking/status command rather than launching the gateway again.
Useful? React with 👍 / 👎.
| if [[ "${START_GATEWAY}" == "true" ]]; then | ||
| cat <<NOTICE | ||
|
|
||
| ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
| [KIROCREW] GATEWAY RUNNING |
There was a problem hiding this comment.
Gate the running notice on service state
This branch is keyed only on START_GATEWAY, but the service start above now deliberately warns and continues when systemctl start fails, such as on the default no-KIRO_API_KEY path or when the port is already occupied. In those cases the pack still prints GATEWAY RUNNING and later gateway running on port ..., so bootstrap can look successful while the dashboard is not reachable; track whether the service actually became active before emitting the running status.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e9d8bc674
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| log "Resolving Kiro API key from Secrets Manager: ${PACK_ARG_FROM_SECRET}" | ||
| SECRET_JSON="$(aws secretsmanager get-secret-value \ | ||
| --secret-id "${PACK_ARG_FROM_SECRET}" \ | ||
| --region "${REGION}" \ |
There was a problem hiding this comment.
Resolve the Kiro secret in its deployment region
When Lowkey is deployed in a region outside the bedrock_allowed list (for example ap-south-1), the new interactive flow creates the secret in DEPLOY_REGION, but build_deploy_params substitutes us-east-1 as BedrockRegion and the CloudFormation UserData passes that value to bootstrap as --region. This lookup therefore searches us-east-1, cannot find the generated regional secret, and aborts the KiroCrew installation; pass the stack/deployment region separately for Secrets Manager access.
Useful? React with 👍 / 👎.
| else | ||
| # Secret name determined now; actual write deferred until after user confirms | ||
| _KIRO_SECRET_NAME="/lowkey/${ENV_NAME}/kiro-api-key" | ||
| KIRO_FROM_SECRET="${_KIRO_SECRET_NAME}" |
There was a problem hiding this comment.
Avoid generating unreadable secrets for restricted profiles
When a user selects account_assistant or personal_assistant and enters an API key at this prompt, the installer passes this secret name to the instance, but the CloudFormation role explicitly denies secretsmanager:GetSecretValue for account_assistant and grants no Secrets Manager access to personal_assistant. KiroCrew then fails during get-secret-value, leaving the stack bootstrap unsuccessful and the newly created secret orphaned; either restrict this flow to a compatible profile or grant narrowly scoped access to the selected secret.
Useful? React with 👍 / 👎.
| PACK_ARG_CHANNEL="$(pack_config_get channel "stable")" | ||
| PACK_ARG_KIROCREW_VERSION="$(pack_config_get kirocrew-version "")" | ||
| PACK_ARG_EXTRAS="$(pack_config_get extras "aws,voice")" | ||
| PACK_ARG_GATEWAY_PORT="$(pack_config_get gateway-port "5476")" | ||
| PACK_ARG_START_GATEWAY="$(pack_config_get start-gateway "true")" |
There was a problem hiding this comment.
Forward KiroCrew settings through bootstrap
In the supported top-level deployment path, these configuration keys can never receive non-default values: repo-wide inspection shows that top-level install.sh parses no KiroCrew channel/version/extras/start flags, and deploy/bootstrap.sh writes none of these keys into PACK_CONFIG. Consequently requests such as nightly channel, a pinned version, or disabling the gateway are silently lost and every normal deployment uses these defaults; add the advertised parameters to the top-level installer, CloudFormation, and bootstrap dispatcher.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6c1a56278
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| User=ec2-user | ||
| Group=ec2-user |
There was a problem hiding this comment.
Template the service user for Ubuntu installs
When this pack is installed on the declared ubuntu2204 platform, the normal account is ubuntu and ec2-user does not exist, so systemd cannot start this unit; the hard-coded home, PATH, and auth-file paths also point at the wrong installation. Resolve the user/home used by the installer and substitute those values into the unit instead of fixing them to the Amazon Linux account.
Useful? React with 👍 / 👎.
| To enable as service: | ||
| sudo systemctl enable --now kirocrew-gateway.service |
There was a problem hiding this comment.
Do not advertise a service that was never installed
When the advertised --start-gateway false path is used, the entire unit templating and copy block is skipped, so this suggested command fails with Unit kirocrew-gateway.service not found. Either install the unit without enabling it in this mode or remove the instruction and tell users how to install the service first.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab9a0efb74
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Condition: KiroCrewWithNewVpc | ||
| Properties: | ||
| VpcId: !Ref VPC | ||
| CidrBlock: '10.0.2.0/24' |
There was a problem hiding this comment.
Derive the second subnet from the configured VPC CIDR
When a KiroCrew deployment uses any supported VpcCidr other than the default 10.0.0.0/16, this hard-coded subnet can fall outside the VPC and CloudFormation rejects it; it can also overlap a valid custom PublicSubnetCidr such as 10.0.2.0/24. Derive or parameterize the second subnet CIDR and validate that both public subnets are distinct members of the selected VPC.
Useful? React with 👍 / 👎.
| DefaultActions: | ||
| - Type: forward | ||
| TargetGroupArn: !Ref KiroCrewTargetGroup |
There was a problem hiding this comment.
Reject direct requests at the ALB listener
In every new-VPC KiroCrew deployment, the ALB security group permits port 80 from 0.0.0.0/0, but this listener forwards all requests without checking the x-origin-verify header. Consequently the generated secret and CloudFront custom header provide no origin protection, and callers can use the exported ALB DNS name to bypass CloudFront's HTTPS policy. Make the default action reject requests and add a forwarding rule that matches the secret header, or otherwise restrict ingress to CloudFront.
Useful? React with 👍 / 👎.
| Type: AWS::ElasticLoadBalancingV2::LoadBalancer | ||
| Condition: KiroCrewWithNewVpc | ||
| Properties: | ||
| Name: !Sub '${EnvironmentName}-kirocrew-alb' |
There was a problem hiding this comment.
Keep generated ALB names within AWS limits
For valid EnvironmentName values longer than 19 characters, ${EnvironmentName}-kirocrew-alb exceeds the 32-character Application Load Balancer name limit, so stack creation fails even though the parameter permits up to 24 characters; the target-group name similarly overflows for longer values. Shorten the generated names or constrain the parameter for KiroCrew deployments.
Useful? React with 👍 / 👎.
| # KiroCrew-specific: show dashboard URL with public IP | ||
| if [[ "${PACK_NAME}" == "kirocrew" && -n "${PUBLIC_IP}" ]]; then | ||
| next_block+="Dashboard:\n" | ||
| next_block+=" http://${PUBLIC_IP}:5476\n\n" |
There was a problem hiding this comment.
Display the CloudFront dashboard URL after deployment
For the normal CLI deployment into a new VPC, the instance security group allows port 5476 only from the ALB security group, so this public-IP URL is unreachable. The usable address is the KiroCrewDashboardUrl CloudFormation output; retrieve that output after stack creation and show it here instead of directing every CLI user to a blocked endpoint.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 655bbf5570
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| else: | ||
| send_response(event, context, 'FAILED', | ||
| f"SSM command {result['Status']}: {result.get('StandardErrorContent', '')[:200]}") | ||
| except Exception as e:\n send_response(event, context, 'FAILED', str(e)[:256]) |
There was a problem hiding this comment.
Replace the literal newline escape in the Lambda source
For every KiroCrew deployment with a new VPC, the inline ZipFile contains the literal characters \n after the except clause rather than an actual newline. Compiling the extracted block produces SyntaxError: unexpected character after line continuation character, so Lambda cannot initialize the handler and KiroCrewDashboardConfigResource never receives a response, causing the stack to fail or time out after provisioning the instance.
Useful? React with 👍 / 👎.
Two-phase pack: - Phase 1: Kiro CLI base (inline, no dep on kiro-cli pack) - Phase 2: KiroCrew gateway layer (upstream installer + systemd service) Features: - Headless auth via --from-secret (Secrets Manager) - AWS MCP proxy configuration - Channel selection (stable/nightly/insider) - pip extras (aws, voice) - Embedding model preload (~610 MB) - systemd service with security hardening - Firewall port management - 73 offline tests passing Refs: https://kiro.dev/docs/crew/installation.md
…d kirocrew to CFN AllowedValues
The installer was cloning default branch (main) and fetching the CFN template from main regardless of REPO_BRANCH. This meant branch testing always hit main's AllowedValues/registry, breaking new pack deploys.
AL2023 AMI has python3 -> 3.9 as system default. The install.sh correctly found python3.11 for KiroCrew, but pipx was installed under 3.9 and the upstream installer also resolved python3 -> 3.9. This caused pipx to crash on 3.10+ syntax (argcomplete uses 'str | bytes' union type). Fix: - Install pipx explicitly under the discovered 3.10+ interpreter - Create /tmp/kirocrew-pybin/python3 symlink so upstream installer resolves the correct Python version
The pack installer only opens the OS-level firewall (firewall-cmd) but the AWS Security Group also needs an inbound rule for the KiroCrew dashboard to be accessible from outside. Added a conditional ingress rule that only applies when PackName=kirocrew.
… start - TEMPLATE_RAW_URL deferred to download time via get_template_url() so REPO_BRANCH is resolved after branch detection (console deploy path) - systemctl start wrapped in if/warn instead of bare call under set -e (prevents recoverable service-start failures from aborting bootstrap)
- Pack install.sh: resolve public IP via IMDS, generate token with 'kirocrew token --ttl 24h', show both in the post-install notice - Top-level install.sh: show dashboard URL (http://<public-ip>:5476) and token generation command in the completion screen for kirocrew - Shell profile: use literal port 5476 in PACK_BANNER_COMMANDS (the shell var wasn't being resolved in the installer's eval context)
KiroCrew defaults to 127.0.0.1 which blocks external access even with the SG port open. Set KIROCREW_HOST=0.0.0.0 in the systemd unit.
Same feature as kiro-cli pack on main — when user interactively selects kirocrew, installer prompts to create/paste a Kiro API key (ksk_... format). Key stored in Secrets Manager, passed as --from-secret to pack install. Condition matches both kiro-cli and kirocrew packs. No pack-level changes needed (kirocrew install.sh already resolves --from-secret → ~/.kiro/env KIRO_API_KEY).
Architecture: CloudFront (HTTPS) → ALB (HTTP, CF-prefix-list locked) → EC2:5476 - Second subnet for ALB multi-AZ - Origin-verify header for defense-in-depth - SG lockdown (no more 0.0.0.0/0 on 5476) - No custom domain needed (*.cloudfront.net) - KiroCrew token auth still active as app-layer security
Adds conditional infrastructure (KiroCrewWithNewVpc) to expose the kirocrew gateway dashboard via CloudFront HTTPS: - Second public subnet (AZ-2) for ALB multi-AZ requirement - Internet-facing ALB (HTTP-only, origin-verify header enforced) - Target group → EC2:5476 with /health check - CloudFront distribution (CachingDisabled for WebSocket support) - Origin-verify secret (auto-generated, stored in Secrets Manager) - EC2 SG locked to ALB-only on port 5476 (new VPC) - Existing VPC fallback: direct 0.0.0.0/0 access preserved No custom domain — uses *.cloudfront.net. Auth: KiroCrew built-in token auth (no Cognito needed).
Critical fixes from KiroCrew docs review: 1. Health check: /health → /api/health (only /api/health, /api/live, /api/ready are token-free; /health returns 401) 2. Post-deploy Custom Resource Lambda: - Fires after CloudFront distribution is created - SSM RunCommand patches ~/.kiro/crew/config.json with dashboard.url - Restarts kirocrew-gateway service - Solves chicken-and-egg: CF URL not known until after deploy 3. Settings via CF: NOT patching KiroCrew source for v1. Config-write endpoints require local request (by design). Users change settings via SSM session.
Docs say KIROCREW_BIND is the correct env var. Set both to be safe since KIROCREW_HOST was never tested externally.
P0 (deploy-breaking): - Fixed literal '\n' in Lambda except block that would cause SyntaxError on Lambda import, hanging the stack for 1 hour before rollback. P2 (functional): - InvocationDoesNotExist: catch inside polling loop (SSM agent race condition during pickup). Add fallback if all 30 iterations fail. - X-Forwarded-Proto: added CloudFront Function (viewer-request) that injects 'x-forwarded-proto: https'. Fixes broken Secure-cookie flag on mobile browsers preventing wss:// upgrade auth per KiroCrew docs.
655bbf5 to
520793c
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 520793c2c0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Runtime: cloudfront-js-2.0 | ||
| FunctionCode: | | ||
| function handler(event) { | ||
| event.request.headers['x-forwarded-proto'] = { value: 'https' }; |
There was a problem hiding this comment.
Avoid setting a disallowed CloudFront header
For every new-VPC KiroCrew dashboard request, this viewer-request function adds x-forwarded-proto, which CloudFront classifies as a disallowed edge-function header. CloudFront therefore fails request validation and returns a 502 before forwarding to the ALB, leaving the only dashboard endpoint exposed by the stack unusable. Pass protocol information through an allowed header (such as CloudFront-Forwarded-Proto) and configure the gateway to consume it instead.
Useful? React with 👍 / 👎.
KiroCrew Pack
Two-phase pack that installs KiroCrew (multi-agent crew gateway) on top of Kiro CLI.
Phase 1 — Kiro CLI Base (inline, no dep)
--from-secret)Phase 2 — KiroCrew Gateway
Files
packs/kirocrew/install.sh— main installer (Phase 1 + Phase 2)packs/kirocrew/manifest.yaml— pack definitionpacks/kirocrew/test.sh— 73 offline tests ✅packs/kirocrew/resources/shell-profile.sh— aliases + bannerpacks/kirocrew/resources/kirocrew-gateway.service— systemd unitKey design decisions
Ref: https://kiro.dev/docs/crew/installation.md