This intentionally small demo lets you use KiroCrew Desktop to run and observe a local-cloud check. The LocalStack Ops app asks its agent to inspect LocalStack, deploy a Terraform S3 → Lambda → DynamoDB flow, run a smoke test, and record the real outcome in the dashboard.
Every AWS-facing component in this demo runs on your computer. LocalStack emulates the AWS APIs used by Terraform; it does not contact a real AWS account. KiroCrew still uses whichever Kiro CLI model provider you have configured, so follow KiroCrew's normal guidance not to place sensitive data in prompts. The optional Run on AWS/EC2 option in KiroCrew is for hosting KiroCrew itself continuously and is outside the scope of this tutorial.
| Component | Where it runs |
|---|---|
| KiroCrew Desktop, dashboard, and schedule | Your computer |
| S3, Lambda, and DynamoDB APIs | LocalStack's Docker container on your computer |
| Terraform deployment and smoke test | This project, through lstk |
Here's what you'll need:
- Docker Desktop (or another Docker engine)
- Terraform
- AWS CLI v2 (
lstk awsruns your installed AWS CLI; on Apple silicon, install the native arm64 build) - Python 3 as
python3(macOS's built-in version is fine); the app uses it to record each run - LocalStack's
lstkCLI - KiroCrew Desktop
- The LocalStack Kiro Power installed and enabled in Kiro so that KiroCrew can use
@localstack.
If you haven't authenticated LocalStack's CLI before, this is the only command-line sign-in step:
lstk loginComplete the normal browser sign-in. The credentials are stored in your system keychain.
This repository includes the prebuilt LocalStack Ops panel in crew-app/ui/dist/, so you don't need to build anything. You do need Node.js (for npx), because the LocalStack MCP server runs through it—the LocalStack Power already requires it.
Open KiroCrew Desktop. On a new installation, complete its initial sign-in/setup flow and decline the optional AWS/EC2 hosting path.
Open Agent Capabilities → MCP Connections and confirm that a localstack connection is present and enabled. If it's missing, enable the LocalStack Power in Kiro and complete the KiroCrew setup flow again before continuing.
This connection is for your own KiroCrew conversations. KiroCrew doesn't share it with app agents, so the LocalStack Ops agent declares its own LocalStack MCP server in crew-app/agents/localstack-ops-agent.json.
-
In the sidebar, open Apps and choose Discover.
-
Select Sources (the gear control in the Discover header).
-
Choose the option to install a local directory.
-
Select the
crew-appfolder inside your clone of this repository—for example,<path-to-clone>/crew-app. Don't select the repository root: the app's manifest,app.json, is increw-app. -
Review the app details and install it.
KiroCrew copies the app into its local app store. It is initially disabled, and Library hides disabled apps by default. If you do not see LocalStack Ops, select Show n disabled apps in Library first. If it is already present, do not install it again; continue with the existing app.
When this repository changes, refresh the installed copy from the Desktop app: in Apps → Library, open LocalStack Ops and select Sync ("Sync app from its source directory"). KiroCrew copies the updated crew-app folder, re-registers the app's agent and skill, and restarts its backend. Recorded runs are kept. The scheduled job keeps a persistent agent session, though, and a session that's already running keeps the agent definition it started with. After a sync, quit KiroCrew Desktop completely (Cmd+Q, not just closing the window) and reopen it before triggering the job, so the next run starts a fresh session with the updated agent. If you only changed the dashboard, use View → Force Reload (Cmd+Shift+R) instead: KiroCrew keeps an app page's code loaded until the window reloads, so a sync alone leaves the old dashboard running.
- In Apps → Library, select Show n disabled apps if necessary, then open LocalStack Ops.
- Read the app's description and review this repository's
crew-app/directory if you have not already. - Select Enable.
- When KiroCrew asks for third-party-app consent, approve LocalStack Ops only.
Enabling registers the app's agent, its @localstack access, its backend, its dashboard page, and the scheduled check.
-
Open Schedule from the sidebar and find
localstack-ops-check. -
Use the job's immediate-run action to start it now. The Schedule execution view shows its progress.
-
Watch for approval requests—they're easy to miss. A scheduled job has no conversation to ask in, so KiroCrew doesn't show its requests in the Schedule view. It plays a notification sound, and the request itself waits in the alerts panel: select the small alert icon to open it, then approve the Approval needed entry. Keep that panel open for the whole first run. Expect a request for each of these:
- the LocalStack MCP status call (and a start call, if LocalStack isn't running),
- the command that runs
scripts/deploy-and-smoke.sh, - the command that records the result.
Reading files is approved automatically.
-
Open LocalStack Ops in the sidebar to see the recorded outcome.
An unanswered request expires after about three minutes and the agent's action is rejected, so stay with the first run. To let later scheduled runs proceed without you, add "cron" to hooks.auto_approve_sources in ~/.kiro/crew/config.json. That opt-in applies to every scheduled job in KiroCrew, not only this one, so decide whether you want it before enabling it.
On a successful run, the dashboard shows Passed and a run record. The agent resolves the original demo source folder before it runs, checks LocalStack through the LocalStack Power, starts it with IAM enforcement if necessary (through the Power when it has an auth token, otherwise with lstk), applies Terraform through lstk, uploads a unique object, and waits for the S3 → Lambda → DynamoDB result. If it fails, the app records the concrete failure and any LocalStack MCP diagnostics instead of claiming success.
The job is installed with its 15-minute schedule switched off, so it only runs when you start it. When you're ready to demonstrate recurring automation, enable it in Schedule—and either add "cron" to hooks.auto_approve_sources or expect a new round of approval requests every 15 minutes. Disable it again when you're done. Cancelling a single run doesn't stop the schedule.
LocalStack only evaluates IAM policies when it's started with ENFORCE_IAM=1. The agent passes ENFORCE_IAM=1 when it starts LocalStack through the Power, and scripts/deploy.sh sets LOCALSTACK_ENFORCE_IAM=1 when it has to start the emulator itself, so the Lambda's role behaves as it would on AWS. That setting only applies at startup: if LocalStack was already running before your first run, run lstk stop once and trigger the job again so the emulator restarts with enforcement.
After recording one passing run:
- Open the LocalStack Ops page and note the passing baseline.
- In
infra/main.tf, delete the statement that allowsdynamodb:PutItemfromaws_iam_role_policy.processor. - Trigger
localstack-ops-checkagain. Terraform applies the narrower policy, the Lambda is denied when it writes to DynamoDB, and the smoke test times out. The agent uses the LocalStack MCP to find the denied action and records a Failed run with that evidence. - Restore the statement, trigger the job once more, and confirm the dashboard returns to Passed.
A scheduled run fails quietly: the Schedule view can show a run as in progress, or as cancelled or failed, with no explanation, and the dashboard simply has no new record. These are the places to look, in order.
-
The alerts panel. Select the small alert icon and look for a pending Approval needed request. This is the most common cause: the agent is waiting for you, and the only other sign is a notification sound.
-
Schedule →
localstack-ops-check→ execution view. The run's status and the agent's final summary.Cancelled by userorprocess not runningmeans the run never reached the recorder. -
KiroCrew's audit log. Every tool call, approval and denial is recorded. This shows which command was waiting and whether its approval expired:
grep -E 'approval_decision|not_auto_approved|Running:' ~/.kiro/crew/security_events.jsonl | tail -20
-
KiroCrew's gateway log. App and MCP problems appear here. For example,
unresolved=@localstackmeans the agent did not receive the LocalStack MCP server:grep -E 'localstack-ops|unresolved=' ~/.kiro/crew/gateway.log | tail -20
-
The scripts themselves. Run
scripts/deploy-and-smoke.shin a terminal. If it fails there, the problem is in your local setup (Docker,lstk, AWS CLI, Terraform), not in KiroCrew.
- No
localstackconnection appears in Agent Capabilities: enable the LocalStack Power/MCP server in Kiro, then repeat the KiroCrew setup flow. Do not enable LocalStack Ops until it appears. - There is no
localstack-ops-checkjob: confirm that LocalStack Ops is enabled in Apps → Library. Disabling an app removes its cron jobs. - The first run cannot reach LocalStack: start Docker Desktop, then run
lstk loginin KiroCrew Desktop's Terminal tab and retry the job. - LocalStack Ops is already installed but not visible: in Apps → Library, select Show n disabled apps, then open it instead of installing a second copy.
- Installing fails with
cannot install while app.json has no readable app identity: you selected a folder without anapp.json, usually the repository root. Install thecrew-appfolder instead. - A run stays in progress and nothing is recorded: the agent is waiting for a tool approval. Approve it from KiroCrew's alerts panel (the small alert icon); if it expired, cancel the run and trigger the job again. See When a run doesn't finish.
- The agent still behaves like the previous version after a Sync: the job reused a session that was already running. Cancel the run, quit KiroCrew Desktop with Cmd+Q, reopen it,, and trigger it again.
- The dashboard stays on Pending or "No runs recorded" after runs pass: the window is still running an older copy of the dashboard. Press Cmd+Shift+R (View → Force Reload). To confirm, open View → Toggle Developer Tools; an
[app-sdk] App "localstack-ops" not permitted to access /api/apps/localstack-ops/historyerror in the Console means the old dashboard code is still loaded. - Approval requests keep arriving after you stop a run: cancelling a run doesn't disable the schedule, and KiroCrew treats the cancelled run's stopped agent as a crash and retries it once. Disable
localstack-ops-checkin Schedule, then let any remaining requests expire. - The run summary says LocalStack was started with
lstkrather than the Power: the Power's start needs aLOCALSTACK_AUTH_TOKEN, and the app's agent runs its own LocalStack MCP server without one. That's expected; the agent still uses the Power to inspect LocalStack and diagnose failures. - The dashboard shows
Could not load run history: make sure LocalStack Ops is enabled and trusted, then reopen the page. KiroCrew only starts a third-party app's backend once the app is trusted. - The smoke test fails with
bad CPU type in executable: your AWS CLI is an Intel build on an Apple silicon Mac without Rosetta (a macOS update can remove it). Install the native arm64 AWS CLI v2 (for example,brew install awscli) or reinstall Rosetta withsoftwareupdate --install-rosetta --agree-to-license, then retry. - Removing
dynamodb:PutItemdoesn't make the run fail: LocalStack was started without IAM enforcement. Runlstk stop, then trigger the job again. - You see warnings about stored defaults or a retired STT provider: those are unrelated KiroCrew configuration-migration notices. Review them separately in Settings; they do not indicate a LocalStack failure.
The desktop tutorial uses the checked-in crew-app/ui/dist/index.mjs bundle. Rebuild it only when editing the React source:
(cd crew-app/ui && npm install --legacy-peer-deps --no-audit --no-fund && npm run build)The Terraform and test scripts remain available for development and debugging:
scripts/deploy-and-smoke.shThe app intentionally uses lstk; it does not use the legacy localstack CLI.