@raindancers/raindancers-crew 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/API.md CHANGED
@@ -211,56 +211,55 @@ The KMS key encrypting the bucket.
211
211
  ---
212
212
 
213
213
 
214
- ### FargateCrew <a name="FargateCrew" id="@raindancers/raindancers-crew.FargateCrew"></a>
214
+ ### CrewWebhookIngress <a name="CrewWebhookIngress" id="@raindancers/raindancers-crew.CrewWebhookIngress"></a>
215
215
 
216
- Per-crew Fargate scaffolding for ONE KiroCrew remote crew: the two roles a task carries and the log group it writes to.
216
+ OPTIONAL, composable webhook-ingress path for {@link EcsCrewHost}, mirroring the optional {@link CrewBackupBucket } shape.
217
217
 
218
- One per crew, alongside the shared {@link FargateCrewBase }. Deleting this
219
- removes exactly one crew's identity and logs and leaves the cluster and its
220
- siblings untouched. Port of the upstream `kirocrew-fargate-crew` template.
218
+ Nothing is created unless the
219
+ consumer instantiates it, so an existing consumer gains no new resources.
221
220
 
222
- Security invariants preserved from upstream:
223
- - The **task role** (the running container's identity, and the blast radius
224
- one agent turn reaches) is created with NO policies and MUST NEVER be
225
- granted `secretsmanager:GetSecretValue` — the model credential is already
226
- in the container env, so the grant buys nothing while letting one turn read
227
- every crew's secret.
228
- - The **execution role** reads secrets scoped to `kirocrew/crew/<crew>/*`
229
- only, with individually-listed actions (no prefix wildcards).
230
- - Both assume-role policies carry an `aws:SourceAccount` condition so the
231
- roles are not assumable on behalf of an unrelated stack's task.
221
+ Because each crew task runs in awsvpc mode with a real private VPC IP, an
222
+ in-VPC Lambda can POST to a crew's `POST /api/hooks/agent` DIRECTLY — no VPC
223
+ endpoint, no PrivateLink, no ALB. This construct wires: an SNS topic, an
224
+ in-VPC Lambda under the permissions boundary, and a scoped ingress rule on
225
+ the crew task security group from the Lambda's SG on the crew port ONLY.
226
+ That ingress rule is the single controlled inbound exception to the
227
+ egress-only task model.
232
228
 
233
- #### Initializers <a name="Initializers" id="@raindancers/raindancers-crew.FargateCrew.Initializer"></a>
229
+ Greenfield: the construct wires the plumbing but ships no webhook-to-crew
230
+ routing opinion — the consumer supplies the Lambda {@link CrewWebhookIngressProps.code}.
231
+
232
+ #### Initializers <a name="Initializers" id="@raindancers/raindancers-crew.CrewWebhookIngress.Initializer"></a>
234
233
 
235
234
  ```typescript
236
- import { FargateCrew } from '@raindancers/raindancers-crew'
235
+ import { CrewWebhookIngress } from '@raindancers/raindancers-crew'
237
236
 
238
- new FargateCrew(scope: Construct, id: string, props: FargateCrewProps)
237
+ new CrewWebhookIngress(scope: Construct, id: string, props: CrewWebhookIngressProps)
239
238
  ```
240
239
 
241
240
  | **Name** | **Type** | **Description** |
242
241
  | --- | --- | --- |
243
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
244
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
245
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.props">props</a></code> | <code><a href="#@raindancers/raindancers-crew.FargateCrewProps">FargateCrewProps</a></code> | *No description.* |
242
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
243
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
244
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.Initializer.parameter.props">props</a></code> | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps">CrewWebhookIngressProps</a></code> | *No description.* |
246
245
 
247
246
  ---
248
247
 
249
- ##### `scope`<sup>Required</sup> <a name="scope" id="@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.scope"></a>
248
+ ##### `scope`<sup>Required</sup> <a name="scope" id="@raindancers/raindancers-crew.CrewWebhookIngress.Initializer.parameter.scope"></a>
250
249
 
251
250
  - *Type:* constructs.Construct
252
251
 
253
252
  ---
254
253
 
255
- ##### `id`<sup>Required</sup> <a name="id" id="@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.id"></a>
254
+ ##### `id`<sup>Required</sup> <a name="id" id="@raindancers/raindancers-crew.CrewWebhookIngress.Initializer.parameter.id"></a>
256
255
 
257
256
  - *Type:* string
258
257
 
259
258
  ---
260
259
 
261
- ##### `props`<sup>Required</sup> <a name="props" id="@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.props"></a>
260
+ ##### `props`<sup>Required</sup> <a name="props" id="@raindancers/raindancers-crew.CrewWebhookIngress.Initializer.parameter.props"></a>
262
261
 
263
- - *Type:* <a href="#@raindancers/raindancers-crew.FargateCrewProps">FargateCrewProps</a>
262
+ - *Type:* <a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps">CrewWebhookIngressProps</a>
264
263
 
265
264
  ---
266
265
 
@@ -268,12 +267,12 @@ new FargateCrew(scope: Construct, id: string, props: FargateCrewProps)
268
267
 
269
268
  | **Name** | **Description** |
270
269
  | --- | --- |
271
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.toString">toString</a></code> | Returns a string representation of this construct. |
272
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.with">with</a></code> | Applies one or more mixins to this construct. |
270
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.toString">toString</a></code> | Returns a string representation of this construct. |
271
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.with">with</a></code> | Applies one or more mixins to this construct. |
273
272
 
274
273
  ---
275
274
 
276
- ##### `toString` <a name="toString" id="@raindancers/raindancers-crew.FargateCrew.toString"></a>
275
+ ##### `toString` <a name="toString" id="@raindancers/raindancers-crew.CrewWebhookIngress.toString"></a>
277
276
 
278
277
  ```typescript
279
278
  public toString(): string
@@ -281,7 +280,7 @@ public toString(): string
281
280
 
282
281
  Returns a string representation of this construct.
283
282
 
284
- ##### `with` <a name="with" id="@raindancers/raindancers-crew.FargateCrew.with"></a>
283
+ ##### `with` <a name="with" id="@raindancers/raindancers-crew.CrewWebhookIngress.with"></a>
285
284
 
286
285
  ```typescript
287
286
  public with(mixins: ...IMixin[]): IConstruct
@@ -294,7 +293,7 @@ start of the call, so constructs added by a mixin will not be visited.
294
293
  Use multiple `with()` calls if subsequent mixins should apply to added
295
294
  constructs.
296
295
 
297
- ###### `mixins`<sup>Required</sup> <a name="mixins" id="@raindancers/raindancers-crew.FargateCrew.with.parameter.mixins"></a>
296
+ ###### `mixins`<sup>Required</sup> <a name="mixins" id="@raindancers/raindancers-crew.CrewWebhookIngress.with.parameter.mixins"></a>
298
297
 
299
298
  - *Type:* ...constructs.IMixin[]
300
299
 
@@ -306,16 +305,16 @@ The mixins to apply.
306
305
 
307
306
  | **Name** | **Description** |
308
307
  | --- | --- |
309
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.isConstruct">isConstruct</a></code> | Checks if `x` is a construct. |
308
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.isConstruct">isConstruct</a></code> | Checks if `x` is a construct. |
310
309
 
311
310
  ---
312
311
 
313
- ##### `isConstruct` <a name="isConstruct" id="@raindancers/raindancers-crew.FargateCrew.isConstruct"></a>
312
+ ##### `isConstruct` <a name="isConstruct" id="@raindancers/raindancers-crew.CrewWebhookIngress.isConstruct"></a>
314
313
 
315
314
  ```typescript
316
- import { FargateCrew } from '@raindancers/raindancers-crew'
315
+ import { CrewWebhookIngress } from '@raindancers/raindancers-crew'
317
316
 
318
- FargateCrew.isConstruct(x: any)
317
+ CrewWebhookIngress.isConstruct(x: any)
319
318
  ```
320
319
 
321
320
  Checks if `x` is a construct.
@@ -334,7 +333,7 @@ library can be accidentally installed, and `instanceof` will behave
334
333
  unpredictably. It is safest to avoid using `instanceof`, and using
335
334
  this type-testing method instead.
336
335
 
337
- ###### `x`<sup>Required</sup> <a name="x" id="@raindancers/raindancers-crew.FargateCrew.isConstruct.parameter.x"></a>
336
+ ###### `x`<sup>Required</sup> <a name="x" id="@raindancers/raindancers-crew.CrewWebhookIngress.isConstruct.parameter.x"></a>
338
337
 
339
338
  - *Type:* any
340
339
 
@@ -346,17 +345,14 @@ Any object.
346
345
 
347
346
  | **Name** | **Type** | **Description** |
348
347
  | --- | --- | --- |
349
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
350
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.crew">crew</a></code> | <code>string</code> | The crew this construct scaffolds. |
351
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.executionRole">executionRole</a></code> | <code>aws-cdk-lib.aws_iam.Role</code> | Role ECS assumes BEFORE the container starts (secret fetch + log stream). |
352
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.logGroup">logGroup</a></code> | <code>aws-cdk-lib.aws_logs.LogGroup</code> | The crew's log group (`/kirocrew/crew/<crew>`). |
353
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.secretArnPattern">secretArnPattern</a></code> | <code>string</code> | The one secret ARN pattern the execution role may read. |
354
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.secretNamePrefix">secretNamePrefix</a></code> | <code>string</code> | Namespace a crew secret must be created under for the exec role to read it. |
355
- | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.taskRole">taskRole</a></code> | <code>aws-cdk-lib.aws_iam.Role</code> | Identity the RUNNING container carries. |
348
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
349
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.property.function">function</a></code> | <code>aws-cdk-lib.aws_lambda.Function</code> | The in-VPC ingress Lambda. |
350
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.property.securityGroup">securityGroup</a></code> | <code>aws-cdk-lib.aws_ec2.SecurityGroup</code> | The ingress Lambda's security group (the source of the scoped task ingress rule). |
351
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngress.property.topic">topic</a></code> | <code>aws-cdk-lib.aws_sns.ITopic</code> | The SNS topic that fans events into the ingress Lambda. |
356
352
 
357
353
  ---
358
354
 
359
- ##### `node`<sup>Required</sup> <a name="node" id="@raindancers/raindancers-crew.FargateCrew.property.node"></a>
355
+ ##### `node`<sup>Required</sup> <a name="node" id="@raindancers/raindancers-crew.CrewWebhookIngress.property.node"></a>
360
356
 
361
357
  ```typescript
362
358
  public readonly node: Node;
@@ -368,122 +364,94 @@ The tree node.
368
364
 
369
365
  ---
370
366
 
371
- ##### `crew`<sup>Required</sup> <a name="crew" id="@raindancers/raindancers-crew.FargateCrew.property.crew"></a>
372
-
373
- ```typescript
374
- public readonly crew: string;
375
- ```
376
-
377
- - *Type:* string
378
-
379
- The crew this construct scaffolds.
380
-
381
- ---
382
-
383
- ##### `executionRole`<sup>Required</sup> <a name="executionRole" id="@raindancers/raindancers-crew.FargateCrew.property.executionRole"></a>
384
-
385
- ```typescript
386
- public readonly executionRole: Role;
387
- ```
388
-
389
- - *Type:* aws-cdk-lib.aws_iam.Role
390
-
391
- Role ECS assumes BEFORE the container starts (secret fetch + log stream).
392
-
393
- ---
394
-
395
- ##### `logGroup`<sup>Required</sup> <a name="logGroup" id="@raindancers/raindancers-crew.FargateCrew.property.logGroup"></a>
367
+ ##### `function`<sup>Required</sup> <a name="function" id="@raindancers/raindancers-crew.CrewWebhookIngress.property.function"></a>
396
368
 
397
369
  ```typescript
398
- public readonly logGroup: LogGroup;
370
+ public readonly function: Function;
399
371
  ```
400
372
 
401
- - *Type:* aws-cdk-lib.aws_logs.LogGroup
373
+ - *Type:* aws-cdk-lib.aws_lambda.Function
402
374
 
403
- The crew's log group (`/kirocrew/crew/<crew>`).
375
+ The in-VPC ingress Lambda.
404
376
 
405
377
  ---
406
378
 
407
- ##### `secretArnPattern`<sup>Required</sup> <a name="secretArnPattern" id="@raindancers/raindancers-crew.FargateCrew.property.secretArnPattern"></a>
379
+ ##### `securityGroup`<sup>Required</sup> <a name="securityGroup" id="@raindancers/raindancers-crew.CrewWebhookIngress.property.securityGroup"></a>
408
380
 
409
381
  ```typescript
410
- public readonly secretArnPattern: string;
382
+ public readonly securityGroup: SecurityGroup;
411
383
  ```
412
384
 
413
- - *Type:* string
385
+ - *Type:* aws-cdk-lib.aws_ec2.SecurityGroup
414
386
 
415
- The one secret ARN pattern the execution role may read.
387
+ The ingress Lambda's security group (the source of the scoped task ingress rule).
416
388
 
417
389
  ---
418
390
 
419
- ##### `secretNamePrefix`<sup>Required</sup> <a name="secretNamePrefix" id="@raindancers/raindancers-crew.FargateCrew.property.secretNamePrefix"></a>
391
+ ##### `topic`<sup>Required</sup> <a name="topic" id="@raindancers/raindancers-crew.CrewWebhookIngress.property.topic"></a>
420
392
 
421
393
  ```typescript
422
- public readonly secretNamePrefix: string;
394
+ public readonly topic: ITopic;
423
395
  ```
424
396
 
425
- - *Type:* string
397
+ - *Type:* aws-cdk-lib.aws_sns.ITopic
426
398
 
427
- Namespace a crew secret must be created under for the exec role to read it.
399
+ The SNS topic that fans events into the ingress Lambda.
428
400
 
429
401
  ---
430
402
 
431
- ##### `taskRole`<sup>Required</sup> <a name="taskRole" id="@raindancers/raindancers-crew.FargateCrew.property.taskRole"></a>
432
-
433
- ```typescript
434
- public readonly taskRole: Role;
435
- ```
436
-
437
- - *Type:* aws-cdk-lib.aws_iam.Role
438
-
439
- Identity the RUNNING container carries.
440
-
441
- Created with no policies.
442
-
443
- ---
444
403
 
404
+ ### EcsCrewHost <a name="EcsCrewHost" id="@raindancers/raindancers-crew.EcsCrewHost"></a>
445
405
 
446
- ### FargateCrewBase <a name="FargateCrewBase" id="@raindancers/raindancers-crew.FargateCrewBase"></a>
406
+ One self-provisioned EC2 host running the ECS agent, hosting `crewCount` Kiro Crew instances as ECS-on-EC2 container tasks.
447
407
 
448
- Shared Fargate scaffolding for KiroCrew remote crews: the ECS cluster every crew task runs on and the egress-only security group they are placed in.
408
+ The host registers to the {@link FargateCrewBase} cluster and does the NAT
409
+ for the crew tasks itself, so the tasks stay fully private with no public
410
+ IPs and no NAT Gateway, fck-nat, VPC endpoints, or ALB. Each task runs in
411
+ awsvpc mode with its own ENI and private VPC IP; each crew keeps its durable
412
+ `~/.kiro/crew` state on its own encrypted EBS volume that survives instance
413
+ replacement.
449
414
 
450
- ONE per account and region. The per-crew roles and log group live in
451
- {@link FargateCrew } (one per crew), so deleting a crew cannot delete the
452
- cluster its siblings run on.
415
+ Isolation is container-level (shared kernel), accepted as sufficient:
416
+ Graviton Nitro protects the box from other AWS tenants, containers cover
417
+ crew-to-crew separation. See the host-OOM caution: hard per-task memory caps
418
+ bound each crew's ceiling but a busy crew can still pressure siblings when
419
+ the sum of actual usage exceeds physical RAM.
453
420
 
454
- Port of the upstream `kirocrew-fargate-base` CloudFormation template.
421
+ `crewCount` defaults to 1, identical to the single-crew shape, so a plain
422
+ instantiation with no new props gains no extra resources.
455
423
 
456
- #### Initializers <a name="Initializers" id="@raindancers/raindancers-crew.FargateCrewBase.Initializer"></a>
424
+ #### Initializers <a name="Initializers" id="@raindancers/raindancers-crew.EcsCrewHost.Initializer"></a>
457
425
 
458
426
  ```typescript
459
- import { FargateCrewBase } from '@raindancers/raindancers-crew'
427
+ import { EcsCrewHost } from '@raindancers/raindancers-crew'
460
428
 
461
- new FargateCrewBase(scope: Construct, id: string, props: FargateCrewBaseProps)
429
+ new EcsCrewHost(scope: Construct, id: string, props: EcsCrewHostProps)
462
430
  ```
463
431
 
464
432
  | **Name** | **Type** | **Description** |
465
433
  | --- | --- | --- |
466
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
467
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
468
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.props">props</a></code> | <code><a href="#@raindancers/raindancers-crew.FargateCrewBaseProps">FargateCrewBaseProps</a></code> | *No description.* |
434
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
435
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
436
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.Initializer.parameter.props">props</a></code> | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps">EcsCrewHostProps</a></code> | *No description.* |
469
437
 
470
438
  ---
471
439
 
472
- ##### `scope`<sup>Required</sup> <a name="scope" id="@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.scope"></a>
440
+ ##### `scope`<sup>Required</sup> <a name="scope" id="@raindancers/raindancers-crew.EcsCrewHost.Initializer.parameter.scope"></a>
473
441
 
474
442
  - *Type:* constructs.Construct
475
443
 
476
444
  ---
477
445
 
478
- ##### `id`<sup>Required</sup> <a name="id" id="@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.id"></a>
446
+ ##### `id`<sup>Required</sup> <a name="id" id="@raindancers/raindancers-crew.EcsCrewHost.Initializer.parameter.id"></a>
479
447
 
480
448
  - *Type:* string
481
449
 
482
450
  ---
483
451
 
484
- ##### `props`<sup>Required</sup> <a name="props" id="@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.props"></a>
452
+ ##### `props`<sup>Required</sup> <a name="props" id="@raindancers/raindancers-crew.EcsCrewHost.Initializer.parameter.props"></a>
485
453
 
486
- - *Type:* <a href="#@raindancers/raindancers-crew.FargateCrewBaseProps">FargateCrewBaseProps</a>
454
+ - *Type:* <a href="#@raindancers/raindancers-crew.EcsCrewHostProps">EcsCrewHostProps</a>
487
455
 
488
456
  ---
489
457
 
@@ -491,12 +459,12 @@ new FargateCrewBase(scope: Construct, id: string, props: FargateCrewBaseProps)
491
459
 
492
460
  | **Name** | **Description** |
493
461
  | --- | --- |
494
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.toString">toString</a></code> | Returns a string representation of this construct. |
495
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.with">with</a></code> | Applies one or more mixins to this construct. |
462
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.toString">toString</a></code> | Returns a string representation of this construct. |
463
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.with">with</a></code> | Applies one or more mixins to this construct. |
496
464
 
497
465
  ---
498
466
 
499
- ##### `toString` <a name="toString" id="@raindancers/raindancers-crew.FargateCrewBase.toString"></a>
467
+ ##### `toString` <a name="toString" id="@raindancers/raindancers-crew.EcsCrewHost.toString"></a>
500
468
 
501
469
  ```typescript
502
470
  public toString(): string
@@ -504,7 +472,7 @@ public toString(): string
504
472
 
505
473
  Returns a string representation of this construct.
506
474
 
507
- ##### `with` <a name="with" id="@raindancers/raindancers-crew.FargateCrewBase.with"></a>
475
+ ##### `with` <a name="with" id="@raindancers/raindancers-crew.EcsCrewHost.with"></a>
508
476
 
509
477
  ```typescript
510
478
  public with(mixins: ...IMixin[]): IConstruct
@@ -517,7 +485,7 @@ start of the call, so constructs added by a mixin will not be visited.
517
485
  Use multiple `with()` calls if subsequent mixins should apply to added
518
486
  constructs.
519
487
 
520
- ###### `mixins`<sup>Required</sup> <a name="mixins" id="@raindancers/raindancers-crew.FargateCrewBase.with.parameter.mixins"></a>
488
+ ###### `mixins`<sup>Required</sup> <a name="mixins" id="@raindancers/raindancers-crew.EcsCrewHost.with.parameter.mixins"></a>
521
489
 
522
490
  - *Type:* ...constructs.IMixin[]
523
491
 
@@ -529,16 +497,16 @@ The mixins to apply.
529
497
 
530
498
  | **Name** | **Description** |
531
499
  | --- | --- |
532
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.isConstruct">isConstruct</a></code> | Checks if `x` is a construct. |
500
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.isConstruct">isConstruct</a></code> | Checks if `x` is a construct. |
533
501
 
534
502
  ---
535
503
 
536
- ##### `isConstruct` <a name="isConstruct" id="@raindancers/raindancers-crew.FargateCrewBase.isConstruct"></a>
504
+ ##### `isConstruct` <a name="isConstruct" id="@raindancers/raindancers-crew.EcsCrewHost.isConstruct"></a>
537
505
 
538
506
  ```typescript
539
- import { FargateCrewBase } from '@raindancers/raindancers-crew'
507
+ import { EcsCrewHost } from '@raindancers/raindancers-crew'
540
508
 
541
- FargateCrewBase.isConstruct(x: any)
509
+ EcsCrewHost.isConstruct(x: any)
542
510
  ```
543
511
 
544
512
  Checks if `x` is a construct.
@@ -557,7 +525,7 @@ library can be accidentally installed, and `instanceof` will behave
557
525
  unpredictably. It is safest to avoid using `instanceof`, and using
558
526
  this type-testing method instead.
559
527
 
560
- ###### `x`<sup>Required</sup> <a name="x" id="@raindancers/raindancers-crew.FargateCrewBase.isConstruct.parameter.x"></a>
528
+ ###### `x`<sup>Required</sup> <a name="x" id="@raindancers/raindancers-crew.EcsCrewHost.isConstruct.parameter.x"></a>
561
529
 
562
530
  - *Type:* any
563
531
 
@@ -569,15 +537,22 @@ Any object.
569
537
 
570
538
  | **Name** | **Type** | **Description** |
571
539
  | --- | --- | --- |
572
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
573
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.cluster">cluster</a></code> | <code>aws-cdk-lib.aws_ecs.Cluster</code> | The ECS cluster crew tasks run on. |
574
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.cpuArchitecture">cpuArchitecture</a></code> | <code><a href="#@raindancers/raindancers-crew.FargateCpuArchitecture">FargateCpuArchitecture</a></code> | The architecture crew images must be built for. |
575
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.securityGroup">securityGroup</a></code> | <code>aws-cdk-lib.aws_ec2.SecurityGroup</code> | The egress-only task security group (no inbound). |
576
- | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.stackTag">stackTag</a></code> | <code>string</code> | The `kirocrew:fargate` discovery tag value. |
540
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
541
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.autoScalingGroup">autoScalingGroup</a></code> | <code>aws-cdk-lib.aws_autoscaling.AutoScalingGroup</code> | The size-1 Auto Scaling Group holding the single ECS-registered EC2 host. |
542
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.base">base</a></code> | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase">FargateCrewBase</a></code> | The shared ECS scaffolding (cluster + egress-only task SG). |
543
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.capacityProvider">capacityProvider</a></code> | <code>aws-cdk-lib.aws_ecs.AsgCapacityProvider</code> | The capacity provider registering the host with the cluster. |
544
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.crewNames">crewNames</a></code> | <code>string[]</code> | The resolved crew names. |
545
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.crews">crews</a></code> | <code><a href="#@raindancers/raindancers-crew.FargateCrew">FargateCrew</a>[]</code> | The per-crew scaffolding (roles + log group), one per crew. |
546
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.dataVolumes">dataVolumes</a></code> | <code><a href="#@raindancers/raindancers-crew.CrewDataVolume">CrewDataVolume</a>[]</code> | The per-crew durable data volumes (device/label/mount metadata). |
547
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.hostSecurityGroup">hostSecurityGroup</a></code> | <code>aws-cdk-lib.aws_ec2.SecurityGroup</code> | The host's SSM-only security group (no inbound). |
548
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.region">region</a></code> | <code>string</code> | The region the host runs in (read from the stack env, never a prop). |
549
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.role">role</a></code> | <code>aws-cdk-lib.aws_iam.Role</code> | The host instance's IAM role (carries the permissions boundary). |
550
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.services">services</a></code> | <code>aws-cdk-lib.aws_ecs.Ec2Service[]</code> | The per-crew EC2 services. |
551
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost.property.stackTag">stackTag</a></code> | <code>string</code> | The discovery tag value written as `kirocrew:ecs-host`. |
577
552
 
578
553
  ---
579
554
 
580
- ##### `node`<sup>Required</sup> <a name="node" id="@raindancers/raindancers-crew.FargateCrewBase.property.node"></a>
555
+ ##### `node`<sup>Required</sup> <a name="node" id="@raindancers/raindancers-crew.EcsCrewHost.property.node"></a>
581
556
 
582
557
  ```typescript
583
558
  public readonly node: Node;
@@ -589,43 +564,127 @@ The tree node.
589
564
 
590
565
  ---
591
566
 
592
- ##### `cluster`<sup>Required</sup> <a name="cluster" id="@raindancers/raindancers-crew.FargateCrewBase.property.cluster"></a>
567
+ ##### `autoScalingGroup`<sup>Required</sup> <a name="autoScalingGroup" id="@raindancers/raindancers-crew.EcsCrewHost.property.autoScalingGroup"></a>
593
568
 
594
569
  ```typescript
595
- public readonly cluster: Cluster;
570
+ public readonly autoScalingGroup: AutoScalingGroup;
596
571
  ```
597
572
 
598
- - *Type:* aws-cdk-lib.aws_ecs.Cluster
573
+ - *Type:* aws-cdk-lib.aws_autoscaling.AutoScalingGroup
599
574
 
600
- The ECS cluster crew tasks run on.
575
+ The size-1 Auto Scaling Group holding the single ECS-registered EC2 host.
601
576
 
602
577
  ---
603
578
 
604
- ##### `cpuArchitecture`<sup>Required</sup> <a name="cpuArchitecture" id="@raindancers/raindancers-crew.FargateCrewBase.property.cpuArchitecture"></a>
579
+ ##### `base`<sup>Required</sup> <a name="base" id="@raindancers/raindancers-crew.EcsCrewHost.property.base"></a>
605
580
 
606
581
  ```typescript
607
- public readonly cpuArchitecture: FargateCpuArchitecture;
582
+ public readonly base: FargateCrewBase;
608
583
  ```
609
584
 
610
- - *Type:* <a href="#@raindancers/raindancers-crew.FargateCpuArchitecture">FargateCpuArchitecture</a>
585
+ - *Type:* <a href="#@raindancers/raindancers-crew.FargateCrewBase">FargateCrewBase</a>
611
586
 
612
- The architecture crew images must be built for.
587
+ The shared ECS scaffolding (cluster + egress-only task SG).
613
588
 
614
589
  ---
615
590
 
616
- ##### `securityGroup`<sup>Required</sup> <a name="securityGroup" id="@raindancers/raindancers-crew.FargateCrewBase.property.securityGroup"></a>
591
+ ##### `capacityProvider`<sup>Required</sup> <a name="capacityProvider" id="@raindancers/raindancers-crew.EcsCrewHost.property.capacityProvider"></a>
617
592
 
618
593
  ```typescript
619
- public readonly securityGroup: SecurityGroup;
594
+ public readonly capacityProvider: AsgCapacityProvider;
595
+ ```
596
+
597
+ - *Type:* aws-cdk-lib.aws_ecs.AsgCapacityProvider
598
+
599
+ The capacity provider registering the host with the cluster.
600
+
601
+ ---
602
+
603
+ ##### `crewNames`<sup>Required</sup> <a name="crewNames" id="@raindancers/raindancers-crew.EcsCrewHost.property.crewNames"></a>
604
+
605
+ ```typescript
606
+ public readonly crewNames: string[];
607
+ ```
608
+
609
+ - *Type:* string[]
610
+
611
+ The resolved crew names.
612
+
613
+ ---
614
+
615
+ ##### `crews`<sup>Required</sup> <a name="crews" id="@raindancers/raindancers-crew.EcsCrewHost.property.crews"></a>
616
+
617
+ ```typescript
618
+ public readonly crews: FargateCrew[];
619
+ ```
620
+
621
+ - *Type:* <a href="#@raindancers/raindancers-crew.FargateCrew">FargateCrew</a>[]
622
+
623
+ The per-crew scaffolding (roles + log group), one per crew.
624
+
625
+ ---
626
+
627
+ ##### `dataVolumes`<sup>Required</sup> <a name="dataVolumes" id="@raindancers/raindancers-crew.EcsCrewHost.property.dataVolumes"></a>
628
+
629
+ ```typescript
630
+ public readonly dataVolumes: CrewDataVolume[];
631
+ ```
632
+
633
+ - *Type:* <a href="#@raindancers/raindancers-crew.CrewDataVolume">CrewDataVolume</a>[]
634
+
635
+ The per-crew durable data volumes (device/label/mount metadata).
636
+
637
+ ---
638
+
639
+ ##### `hostSecurityGroup`<sup>Required</sup> <a name="hostSecurityGroup" id="@raindancers/raindancers-crew.EcsCrewHost.property.hostSecurityGroup"></a>
640
+
641
+ ```typescript
642
+ public readonly hostSecurityGroup: SecurityGroup;
620
643
  ```
621
644
 
622
645
  - *Type:* aws-cdk-lib.aws_ec2.SecurityGroup
623
646
 
624
- The egress-only task security group (no inbound).
647
+ The host's SSM-only security group (no inbound).
625
648
 
626
649
  ---
627
650
 
628
- ##### `stackTag`<sup>Required</sup> <a name="stackTag" id="@raindancers/raindancers-crew.FargateCrewBase.property.stackTag"></a>
651
+ ##### `region`<sup>Required</sup> <a name="region" id="@raindancers/raindancers-crew.EcsCrewHost.property.region"></a>
652
+
653
+ ```typescript
654
+ public readonly region: string;
655
+ ```
656
+
657
+ - *Type:* string
658
+
659
+ The region the host runs in (read from the stack env, never a prop).
660
+
661
+ ---
662
+
663
+ ##### `role`<sup>Required</sup> <a name="role" id="@raindancers/raindancers-crew.EcsCrewHost.property.role"></a>
664
+
665
+ ```typescript
666
+ public readonly role: Role;
667
+ ```
668
+
669
+ - *Type:* aws-cdk-lib.aws_iam.Role
670
+
671
+ The host instance's IAM role (carries the permissions boundary).
672
+
673
+ ---
674
+
675
+ ##### `services`<sup>Required</sup> <a name="services" id="@raindancers/raindancers-crew.EcsCrewHost.property.services"></a>
676
+
677
+ ```typescript
678
+ public readonly services: Ec2Service[];
679
+ ```
680
+
681
+ - *Type:* aws-cdk-lib.aws_ecs.Ec2Service[]
682
+
683
+ The per-crew EC2 services.
684
+
685
+ ---
686
+
687
+ ##### `stackTag`<sup>Required</sup> <a name="stackTag" id="@raindancers/raindancers-crew.EcsCrewHost.property.stackTag"></a>
629
688
 
630
689
  ```typescript
631
690
  public readonly stackTag: string;
@@ -633,58 +692,61 @@ public readonly stackTag: string;
633
692
 
634
693
  - *Type:* string
635
694
 
636
- The `kirocrew:fargate` discovery tag value.
695
+ The discovery tag value written as `kirocrew:ecs-host`.
637
696
 
638
697
  ---
639
698
 
640
699
 
641
- ### RemoteCrewInstance <a name="RemoteCrewInstance" id="@raindancers/raindancers-crew.RemoteCrewInstance"></a>
700
+ ### FargateCrew <a name="FargateCrew" id="@raindancers/raindancers-crew.FargateCrew"></a>
642
701
 
643
- A self-hosted KiroCrew gateway on a single EC2 instance, reached over SSM Session Manager with no inbound ports.
702
+ Per-crew Fargate scaffolding for ONE KiroCrew remote crew: the two roles a task carries and the log group it writes to.
644
703
 
645
- This is a pipeline-native, version-controlled CDK port of the upstream
646
- `kirocrew-ec2` CloudFormation template
647
- (github.com/kirodotdev/KiroCrew). It provisions the same shape — an IAM
648
- role (SSM core + optional scoped S3 read) under a required permissions
649
- boundary, an SSM-only security group, an IMDSv2-enforced instance on an
650
- encrypted gp3 volume, and a WaitCondition that blocks stack completion
651
- until the gateway is serving — but under your naming, boundary, and
652
- deploy pipeline instead of an imperative `kirocrew cloud launch`.
704
+ One per crew, alongside the shared {@link FargateCrewBase }. Deleting this
705
+ removes exactly one crew's identity and logs and leaves the cluster and its
706
+ siblings untouched. Port of the upstream `kirocrew-fargate-crew` template.
653
707
 
654
- Access is via SSM port-forward only; the public DNS output is for
655
- diagnostics.
708
+ Security invariants preserved from upstream:
709
+ - The **task role** (the running container's identity, and the blast radius
710
+ one agent turn reaches) is created with NO policies and MUST NEVER be
711
+ granted `secretsmanager:GetSecretValue` — the model credential is already
712
+ in the container env, so the grant buys nothing while letting one turn read
713
+ every crew's secret.
714
+ - The **execution role** reads secrets scoped to `kirocrew/crew/<crew>/*`
715
+ only, with individually-listed actions (no prefix wildcards).
716
+ - Both assume-role policies carry an `aws:SourceAccount` condition so the
717
+ roles are not assumable on behalf of an unrelated stack's task.
656
718
 
657
- #### Initializers <a name="Initializers" id="@raindancers/raindancers-crew.RemoteCrewInstance.Initializer"></a>
719
+ #### Initializers <a name="Initializers" id="@raindancers/raindancers-crew.FargateCrew.Initializer"></a>
658
720
 
659
721
  ```typescript
660
- import { RemoteCrewInstance } from '@raindancers/raindancers-crew'
722
+ import { FargateCrew } from '@raindancers/raindancers-crew'
661
723
 
662
- new RemoteCrewInstance(scope: Construct, id: string, props: RemoteCrewInstanceProps)
724
+ new FargateCrew(scope: Construct, id: string, props: FargateCrewProps)
663
725
  ```
664
726
 
665
727
  | **Name** | **Type** | **Description** |
666
728
  | --- | --- | --- |
667
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
668
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
669
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.props">props</a></code> | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstanceProps">RemoteCrewInstanceProps</a></code> | *No description.* |
729
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
730
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
731
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.props">props</a></code> | <code><a href="#@raindancers/raindancers-crew.FargateCrewProps">FargateCrewProps</a></code> | *No description.* |
670
732
 
671
733
  ---
672
734
 
673
- ##### `scope`<sup>Required</sup> <a name="scope" id="@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.scope"></a>
735
+ ##### `scope`<sup>Required</sup> <a name="scope" id="@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.scope"></a>
674
736
 
675
737
  - *Type:* constructs.Construct
676
738
 
677
739
  ---
678
740
 
679
- ##### `id`<sup>Required</sup> <a name="id" id="@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.id"></a>
741
+ ##### `id`<sup>Required</sup> <a name="id" id="@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.id"></a>
680
742
 
681
743
  - *Type:* string
682
744
 
683
745
  ---
684
746
 
685
- ##### `props`<sup>Required</sup> <a name="props" id="@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.props"></a>
747
+ ##### `props`<sup>Required</sup> <a name="props" id="@raindancers/raindancers-crew.FargateCrew.Initializer.parameter.props"></a>
686
748
 
687
- - *Type:* <a href="#@raindancers/raindancers-crew.RemoteCrewInstanceProps">RemoteCrewInstanceProps</a>
749
+ - *Type:* <a href="#@raindancers/raindancers-crew.FargateCrewProps">FargateCrewProps</a>
688
750
 
689
751
  ---
690
752
 
@@ -692,12 +754,12 @@ new RemoteCrewInstance(scope: Construct, id: string, props: RemoteCrewInstancePr
692
754
 
693
755
  | **Name** | **Description** |
694
756
  | --- | --- |
695
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.toString">toString</a></code> | Returns a string representation of this construct. |
696
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.with">with</a></code> | Applies one or more mixins to this construct. |
757
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.toString">toString</a></code> | Returns a string representation of this construct. |
758
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.with">with</a></code> | Applies one or more mixins to this construct. |
697
759
 
698
760
  ---
699
761
 
700
- ##### `toString` <a name="toString" id="@raindancers/raindancers-crew.RemoteCrewInstance.toString"></a>
762
+ ##### `toString` <a name="toString" id="@raindancers/raindancers-crew.FargateCrew.toString"></a>
701
763
 
702
764
  ```typescript
703
765
  public toString(): string
@@ -705,7 +767,7 @@ public toString(): string
705
767
 
706
768
  Returns a string representation of this construct.
707
769
 
708
- ##### `with` <a name="with" id="@raindancers/raindancers-crew.RemoteCrewInstance.with"></a>
770
+ ##### `with` <a name="with" id="@raindancers/raindancers-crew.FargateCrew.with"></a>
709
771
 
710
772
  ```typescript
711
773
  public with(mixins: ...IMixin[]): IConstruct
@@ -718,7 +780,431 @@ start of the call, so constructs added by a mixin will not be visited.
718
780
  Use multiple `with()` calls if subsequent mixins should apply to added
719
781
  constructs.
720
782
 
721
- ###### `mixins`<sup>Required</sup> <a name="mixins" id="@raindancers/raindancers-crew.RemoteCrewInstance.with.parameter.mixins"></a>
783
+ ###### `mixins`<sup>Required</sup> <a name="mixins" id="@raindancers/raindancers-crew.FargateCrew.with.parameter.mixins"></a>
784
+
785
+ - *Type:* ...constructs.IMixin[]
786
+
787
+ The mixins to apply.
788
+
789
+ ---
790
+
791
+ #### Static Functions <a name="Static Functions" id="Static Functions"></a>
792
+
793
+ | **Name** | **Description** |
794
+ | --- | --- |
795
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.isConstruct">isConstruct</a></code> | Checks if `x` is a construct. |
796
+
797
+ ---
798
+
799
+ ##### `isConstruct` <a name="isConstruct" id="@raindancers/raindancers-crew.FargateCrew.isConstruct"></a>
800
+
801
+ ```typescript
802
+ import { FargateCrew } from '@raindancers/raindancers-crew'
803
+
804
+ FargateCrew.isConstruct(x: any)
805
+ ```
806
+
807
+ Checks if `x` is a construct.
808
+
809
+ Use this method instead of `instanceof` to properly detect `Construct`
810
+ instances, even when the construct library is symlinked.
811
+
812
+ Explanation: in JavaScript, multiple copies of the `constructs` library on
813
+ disk are seen as independent, completely different libraries. As a
814
+ consequence, the class `Construct` in each copy of the `constructs` library
815
+ is seen as a different class, and an instance of one class will not test as
816
+ `instanceof` the other class. `npm install` will not create installations
817
+ like this, but users may manually symlink construct libraries together or
818
+ use a monorepo tool: in those cases, multiple copies of the `constructs`
819
+ library can be accidentally installed, and `instanceof` will behave
820
+ unpredictably. It is safest to avoid using `instanceof`, and using
821
+ this type-testing method instead.
822
+
823
+ ###### `x`<sup>Required</sup> <a name="x" id="@raindancers/raindancers-crew.FargateCrew.isConstruct.parameter.x"></a>
824
+
825
+ - *Type:* any
826
+
827
+ Any object.
828
+
829
+ ---
830
+
831
+ #### Properties <a name="Properties" id="Properties"></a>
832
+
833
+ | **Name** | **Type** | **Description** |
834
+ | --- | --- | --- |
835
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
836
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.crew">crew</a></code> | <code>string</code> | The crew this construct scaffolds. |
837
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.executionRole">executionRole</a></code> | <code>aws-cdk-lib.aws_iam.Role</code> | Role ECS assumes BEFORE the container starts (secret fetch + log stream). |
838
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.logGroup">logGroup</a></code> | <code>aws-cdk-lib.aws_logs.LogGroup</code> | The crew's log group (`/kirocrew/crew/<crew>`). |
839
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.secretArnPattern">secretArnPattern</a></code> | <code>string</code> | The one secret ARN pattern the execution role may read. |
840
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.secretNamePrefix">secretNamePrefix</a></code> | <code>string</code> | Namespace a crew secret must be created under for the exec role to read it. |
841
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrew.property.taskRole">taskRole</a></code> | <code>aws-cdk-lib.aws_iam.Role</code> | Identity the RUNNING container carries. |
842
+
843
+ ---
844
+
845
+ ##### `node`<sup>Required</sup> <a name="node" id="@raindancers/raindancers-crew.FargateCrew.property.node"></a>
846
+
847
+ ```typescript
848
+ public readonly node: Node;
849
+ ```
850
+
851
+ - *Type:* constructs.Node
852
+
853
+ The tree node.
854
+
855
+ ---
856
+
857
+ ##### `crew`<sup>Required</sup> <a name="crew" id="@raindancers/raindancers-crew.FargateCrew.property.crew"></a>
858
+
859
+ ```typescript
860
+ public readonly crew: string;
861
+ ```
862
+
863
+ - *Type:* string
864
+
865
+ The crew this construct scaffolds.
866
+
867
+ ---
868
+
869
+ ##### `executionRole`<sup>Required</sup> <a name="executionRole" id="@raindancers/raindancers-crew.FargateCrew.property.executionRole"></a>
870
+
871
+ ```typescript
872
+ public readonly executionRole: Role;
873
+ ```
874
+
875
+ - *Type:* aws-cdk-lib.aws_iam.Role
876
+
877
+ Role ECS assumes BEFORE the container starts (secret fetch + log stream).
878
+
879
+ ---
880
+
881
+ ##### `logGroup`<sup>Required</sup> <a name="logGroup" id="@raindancers/raindancers-crew.FargateCrew.property.logGroup"></a>
882
+
883
+ ```typescript
884
+ public readonly logGroup: LogGroup;
885
+ ```
886
+
887
+ - *Type:* aws-cdk-lib.aws_logs.LogGroup
888
+
889
+ The crew's log group (`/kirocrew/crew/<crew>`).
890
+
891
+ ---
892
+
893
+ ##### `secretArnPattern`<sup>Required</sup> <a name="secretArnPattern" id="@raindancers/raindancers-crew.FargateCrew.property.secretArnPattern"></a>
894
+
895
+ ```typescript
896
+ public readonly secretArnPattern: string;
897
+ ```
898
+
899
+ - *Type:* string
900
+
901
+ The one secret ARN pattern the execution role may read.
902
+
903
+ ---
904
+
905
+ ##### `secretNamePrefix`<sup>Required</sup> <a name="secretNamePrefix" id="@raindancers/raindancers-crew.FargateCrew.property.secretNamePrefix"></a>
906
+
907
+ ```typescript
908
+ public readonly secretNamePrefix: string;
909
+ ```
910
+
911
+ - *Type:* string
912
+
913
+ Namespace a crew secret must be created under for the exec role to read it.
914
+
915
+ ---
916
+
917
+ ##### `taskRole`<sup>Required</sup> <a name="taskRole" id="@raindancers/raindancers-crew.FargateCrew.property.taskRole"></a>
918
+
919
+ ```typescript
920
+ public readonly taskRole: Role;
921
+ ```
922
+
923
+ - *Type:* aws-cdk-lib.aws_iam.Role
924
+
925
+ Identity the RUNNING container carries.
926
+
927
+ Created with no policies.
928
+
929
+ ---
930
+
931
+
932
+ ### FargateCrewBase <a name="FargateCrewBase" id="@raindancers/raindancers-crew.FargateCrewBase"></a>
933
+
934
+ Shared Fargate scaffolding for KiroCrew remote crews: the ECS cluster every crew task runs on and the egress-only security group they are placed in.
935
+
936
+ ONE per account and region. The per-crew roles and log group live in
937
+ {@link FargateCrew } (one per crew), so deleting a crew cannot delete the
938
+ cluster its siblings run on.
939
+
940
+ Port of the upstream `kirocrew-fargate-base` CloudFormation template.
941
+
942
+ #### Initializers <a name="Initializers" id="@raindancers/raindancers-crew.FargateCrewBase.Initializer"></a>
943
+
944
+ ```typescript
945
+ import { FargateCrewBase } from '@raindancers/raindancers-crew'
946
+
947
+ new FargateCrewBase(scope: Construct, id: string, props: FargateCrewBaseProps)
948
+ ```
949
+
950
+ | **Name** | **Type** | **Description** |
951
+ | --- | --- | --- |
952
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
953
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
954
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.props">props</a></code> | <code><a href="#@raindancers/raindancers-crew.FargateCrewBaseProps">FargateCrewBaseProps</a></code> | *No description.* |
955
+
956
+ ---
957
+
958
+ ##### `scope`<sup>Required</sup> <a name="scope" id="@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.scope"></a>
959
+
960
+ - *Type:* constructs.Construct
961
+
962
+ ---
963
+
964
+ ##### `id`<sup>Required</sup> <a name="id" id="@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.id"></a>
965
+
966
+ - *Type:* string
967
+
968
+ ---
969
+
970
+ ##### `props`<sup>Required</sup> <a name="props" id="@raindancers/raindancers-crew.FargateCrewBase.Initializer.parameter.props"></a>
971
+
972
+ - *Type:* <a href="#@raindancers/raindancers-crew.FargateCrewBaseProps">FargateCrewBaseProps</a>
973
+
974
+ ---
975
+
976
+ #### Methods <a name="Methods" id="Methods"></a>
977
+
978
+ | **Name** | **Description** |
979
+ | --- | --- |
980
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.toString">toString</a></code> | Returns a string representation of this construct. |
981
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.with">with</a></code> | Applies one or more mixins to this construct. |
982
+
983
+ ---
984
+
985
+ ##### `toString` <a name="toString" id="@raindancers/raindancers-crew.FargateCrewBase.toString"></a>
986
+
987
+ ```typescript
988
+ public toString(): string
989
+ ```
990
+
991
+ Returns a string representation of this construct.
992
+
993
+ ##### `with` <a name="with" id="@raindancers/raindancers-crew.FargateCrewBase.with"></a>
994
+
995
+ ```typescript
996
+ public with(mixins: ...IMixin[]): IConstruct
997
+ ```
998
+
999
+ Applies one or more mixins to this construct.
1000
+
1001
+ Mixins are applied in order. The list of constructs is captured at the
1002
+ start of the call, so constructs added by a mixin will not be visited.
1003
+ Use multiple `with()` calls if subsequent mixins should apply to added
1004
+ constructs.
1005
+
1006
+ ###### `mixins`<sup>Required</sup> <a name="mixins" id="@raindancers/raindancers-crew.FargateCrewBase.with.parameter.mixins"></a>
1007
+
1008
+ - *Type:* ...constructs.IMixin[]
1009
+
1010
+ The mixins to apply.
1011
+
1012
+ ---
1013
+
1014
+ #### Static Functions <a name="Static Functions" id="Static Functions"></a>
1015
+
1016
+ | **Name** | **Description** |
1017
+ | --- | --- |
1018
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.isConstruct">isConstruct</a></code> | Checks if `x` is a construct. |
1019
+
1020
+ ---
1021
+
1022
+ ##### `isConstruct` <a name="isConstruct" id="@raindancers/raindancers-crew.FargateCrewBase.isConstruct"></a>
1023
+
1024
+ ```typescript
1025
+ import { FargateCrewBase } from '@raindancers/raindancers-crew'
1026
+
1027
+ FargateCrewBase.isConstruct(x: any)
1028
+ ```
1029
+
1030
+ Checks if `x` is a construct.
1031
+
1032
+ Use this method instead of `instanceof` to properly detect `Construct`
1033
+ instances, even when the construct library is symlinked.
1034
+
1035
+ Explanation: in JavaScript, multiple copies of the `constructs` library on
1036
+ disk are seen as independent, completely different libraries. As a
1037
+ consequence, the class `Construct` in each copy of the `constructs` library
1038
+ is seen as a different class, and an instance of one class will not test as
1039
+ `instanceof` the other class. `npm install` will not create installations
1040
+ like this, but users may manually symlink construct libraries together or
1041
+ use a monorepo tool: in those cases, multiple copies of the `constructs`
1042
+ library can be accidentally installed, and `instanceof` will behave
1043
+ unpredictably. It is safest to avoid using `instanceof`, and using
1044
+ this type-testing method instead.
1045
+
1046
+ ###### `x`<sup>Required</sup> <a name="x" id="@raindancers/raindancers-crew.FargateCrewBase.isConstruct.parameter.x"></a>
1047
+
1048
+ - *Type:* any
1049
+
1050
+ Any object.
1051
+
1052
+ ---
1053
+
1054
+ #### Properties <a name="Properties" id="Properties"></a>
1055
+
1056
+ | **Name** | **Type** | **Description** |
1057
+ | --- | --- | --- |
1058
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
1059
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.cluster">cluster</a></code> | <code>aws-cdk-lib.aws_ecs.Cluster</code> | The ECS cluster crew tasks run on. |
1060
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.cpuArchitecture">cpuArchitecture</a></code> | <code><a href="#@raindancers/raindancers-crew.FargateCpuArchitecture">FargateCpuArchitecture</a></code> | The architecture crew images must be built for. |
1061
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.securityGroup">securityGroup</a></code> | <code>aws-cdk-lib.aws_ec2.SecurityGroup</code> | The egress-only task security group (no inbound). |
1062
+ | <code><a href="#@raindancers/raindancers-crew.FargateCrewBase.property.stackTag">stackTag</a></code> | <code>string</code> | The `kirocrew:fargate` discovery tag value. |
1063
+
1064
+ ---
1065
+
1066
+ ##### `node`<sup>Required</sup> <a name="node" id="@raindancers/raindancers-crew.FargateCrewBase.property.node"></a>
1067
+
1068
+ ```typescript
1069
+ public readonly node: Node;
1070
+ ```
1071
+
1072
+ - *Type:* constructs.Node
1073
+
1074
+ The tree node.
1075
+
1076
+ ---
1077
+
1078
+ ##### `cluster`<sup>Required</sup> <a name="cluster" id="@raindancers/raindancers-crew.FargateCrewBase.property.cluster"></a>
1079
+
1080
+ ```typescript
1081
+ public readonly cluster: Cluster;
1082
+ ```
1083
+
1084
+ - *Type:* aws-cdk-lib.aws_ecs.Cluster
1085
+
1086
+ The ECS cluster crew tasks run on.
1087
+
1088
+ ---
1089
+
1090
+ ##### `cpuArchitecture`<sup>Required</sup> <a name="cpuArchitecture" id="@raindancers/raindancers-crew.FargateCrewBase.property.cpuArchitecture"></a>
1091
+
1092
+ ```typescript
1093
+ public readonly cpuArchitecture: FargateCpuArchitecture;
1094
+ ```
1095
+
1096
+ - *Type:* <a href="#@raindancers/raindancers-crew.FargateCpuArchitecture">FargateCpuArchitecture</a>
1097
+
1098
+ The architecture crew images must be built for.
1099
+
1100
+ ---
1101
+
1102
+ ##### `securityGroup`<sup>Required</sup> <a name="securityGroup" id="@raindancers/raindancers-crew.FargateCrewBase.property.securityGroup"></a>
1103
+
1104
+ ```typescript
1105
+ public readonly securityGroup: SecurityGroup;
1106
+ ```
1107
+
1108
+ - *Type:* aws-cdk-lib.aws_ec2.SecurityGroup
1109
+
1110
+ The egress-only task security group (no inbound).
1111
+
1112
+ ---
1113
+
1114
+ ##### `stackTag`<sup>Required</sup> <a name="stackTag" id="@raindancers/raindancers-crew.FargateCrewBase.property.stackTag"></a>
1115
+
1116
+ ```typescript
1117
+ public readonly stackTag: string;
1118
+ ```
1119
+
1120
+ - *Type:* string
1121
+
1122
+ The `kirocrew:fargate` discovery tag value.
1123
+
1124
+ ---
1125
+
1126
+
1127
+ ### RemoteCrewInstance <a name="RemoteCrewInstance" id="@raindancers/raindancers-crew.RemoteCrewInstance"></a>
1128
+
1129
+ A self-hosted KiroCrew gateway on a single EC2 instance, reached over SSM Session Manager with no inbound ports.
1130
+
1131
+ This is a pipeline-native, version-controlled CDK port of the upstream
1132
+ `kirocrew-ec2` CloudFormation template
1133
+ (github.com/kirodotdev/KiroCrew). It provisions the same shape — an IAM
1134
+ role (SSM core + optional scoped S3 read) under a required permissions
1135
+ boundary, an SSM-only security group, an IMDSv2-enforced instance on an
1136
+ encrypted gp3 volume, and a WaitCondition that blocks stack completion
1137
+ until the gateway is serving — but under your naming, boundary, and
1138
+ deploy pipeline instead of an imperative `kirocrew cloud launch`.
1139
+
1140
+ Access is via SSM port-forward only; the public DNS output is for
1141
+ diagnostics.
1142
+
1143
+ #### Initializers <a name="Initializers" id="@raindancers/raindancers-crew.RemoteCrewInstance.Initializer"></a>
1144
+
1145
+ ```typescript
1146
+ import { RemoteCrewInstance } from '@raindancers/raindancers-crew'
1147
+
1148
+ new RemoteCrewInstance(scope: Construct, id: string, props: RemoteCrewInstanceProps)
1149
+ ```
1150
+
1151
+ | **Name** | **Type** | **Description** |
1152
+ | --- | --- | --- |
1153
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
1154
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
1155
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.props">props</a></code> | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstanceProps">RemoteCrewInstanceProps</a></code> | *No description.* |
1156
+
1157
+ ---
1158
+
1159
+ ##### `scope`<sup>Required</sup> <a name="scope" id="@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.scope"></a>
1160
+
1161
+ - *Type:* constructs.Construct
1162
+
1163
+ ---
1164
+
1165
+ ##### `id`<sup>Required</sup> <a name="id" id="@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.id"></a>
1166
+
1167
+ - *Type:* string
1168
+
1169
+ ---
1170
+
1171
+ ##### `props`<sup>Required</sup> <a name="props" id="@raindancers/raindancers-crew.RemoteCrewInstance.Initializer.parameter.props"></a>
1172
+
1173
+ - *Type:* <a href="#@raindancers/raindancers-crew.RemoteCrewInstanceProps">RemoteCrewInstanceProps</a>
1174
+
1175
+ ---
1176
+
1177
+ #### Methods <a name="Methods" id="Methods"></a>
1178
+
1179
+ | **Name** | **Description** |
1180
+ | --- | --- |
1181
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.toString">toString</a></code> | Returns a string representation of this construct. |
1182
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.with">with</a></code> | Applies one or more mixins to this construct. |
1183
+
1184
+ ---
1185
+
1186
+ ##### `toString` <a name="toString" id="@raindancers/raindancers-crew.RemoteCrewInstance.toString"></a>
1187
+
1188
+ ```typescript
1189
+ public toString(): string
1190
+ ```
1191
+
1192
+ Returns a string representation of this construct.
1193
+
1194
+ ##### `with` <a name="with" id="@raindancers/raindancers-crew.RemoteCrewInstance.with"></a>
1195
+
1196
+ ```typescript
1197
+ public with(mixins: ...IMixin[]): IConstruct
1198
+ ```
1199
+
1200
+ Applies one or more mixins to this construct.
1201
+
1202
+ Mixins are applied in order. The list of constructs is captured at the
1203
+ start of the call, so constructs added by a mixin will not be visited.
1204
+ Use multiple `with()` calls if subsequent mixins should apply to added
1205
+ constructs.
1206
+
1207
+ ###### `mixins`<sup>Required</sup> <a name="mixins" id="@raindancers/raindancers-crew.RemoteCrewInstance.with.parameter.mixins"></a>
722
1208
 
723
1209
  - *Type:* ...constructs.IMixin[]
724
1210
 
@@ -734,353 +1220,1000 @@ The mixins to apply.
734
1220
 
735
1221
  ---
736
1222
 
737
- ##### `isConstruct` <a name="isConstruct" id="@raindancers/raindancers-crew.RemoteCrewInstance.isConstruct"></a>
1223
+ ##### `isConstruct` <a name="isConstruct" id="@raindancers/raindancers-crew.RemoteCrewInstance.isConstruct"></a>
1224
+
1225
+ ```typescript
1226
+ import { RemoteCrewInstance } from '@raindancers/raindancers-crew'
1227
+
1228
+ RemoteCrewInstance.isConstruct(x: any)
1229
+ ```
1230
+
1231
+ Checks if `x` is a construct.
1232
+
1233
+ Use this method instead of `instanceof` to properly detect `Construct`
1234
+ instances, even when the construct library is symlinked.
1235
+
1236
+ Explanation: in JavaScript, multiple copies of the `constructs` library on
1237
+ disk are seen as independent, completely different libraries. As a
1238
+ consequence, the class `Construct` in each copy of the `constructs` library
1239
+ is seen as a different class, and an instance of one class will not test as
1240
+ `instanceof` the other class. `npm install` will not create installations
1241
+ like this, but users may manually symlink construct libraries together or
1242
+ use a monorepo tool: in those cases, multiple copies of the `constructs`
1243
+ library can be accidentally installed, and `instanceof` will behave
1244
+ unpredictably. It is safest to avoid using `instanceof`, and using
1245
+ this type-testing method instead.
1246
+
1247
+ ###### `x`<sup>Required</sup> <a name="x" id="@raindancers/raindancers-crew.RemoteCrewInstance.isConstruct.parameter.x"></a>
1248
+
1249
+ - *Type:* any
1250
+
1251
+ Any object.
1252
+
1253
+ ---
1254
+
1255
+ #### Properties <a name="Properties" id="Properties"></a>
1256
+
1257
+ | **Name** | **Type** | **Description** |
1258
+ | --- | --- | --- |
1259
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
1260
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.instance">instance</a></code> | <code>aws-cdk-lib.aws_ec2.Instance</code> | The EC2 instance (SSM target). |
1261
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.instanceId">instanceId</a></code> | <code>string</code> | Instance id — the SSM target. |
1262
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.publicDnsName">publicDnsName</a></code> | <code>string</code> | Public DNS of the instance (diagnostics only; |
1263
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.role">role</a></code> | <code>aws-cdk-lib.aws_iam.Role</code> | The instance's IAM role (carries the permissions boundary). |
1264
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.securityGroup">securityGroup</a></code> | <code>aws-cdk-lib.aws_ec2.SecurityGroup</code> | The SSM-only security group (no inbound unless allowSshCidr is set). |
1265
+ | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.stackTag">stackTag</a></code> | <code>string</code> | The discovery tag value written as `kirocrew:instance`. |
1266
+
1267
+ ---
1268
+
1269
+ ##### `node`<sup>Required</sup> <a name="node" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.node"></a>
1270
+
1271
+ ```typescript
1272
+ public readonly node: Node;
1273
+ ```
1274
+
1275
+ - *Type:* constructs.Node
1276
+
1277
+ The tree node.
1278
+
1279
+ ---
1280
+
1281
+ ##### `instance`<sup>Required</sup> <a name="instance" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.instance"></a>
1282
+
1283
+ ```typescript
1284
+ public readonly instance: Instance;
1285
+ ```
1286
+
1287
+ - *Type:* aws-cdk-lib.aws_ec2.Instance
1288
+
1289
+ The EC2 instance (SSM target).
1290
+
1291
+ ---
1292
+
1293
+ ##### `instanceId`<sup>Required</sup> <a name="instanceId" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.instanceId"></a>
1294
+
1295
+ ```typescript
1296
+ public readonly instanceId: string;
1297
+ ```
1298
+
1299
+ - *Type:* string
1300
+
1301
+ Instance id — the SSM target.
1302
+
1303
+ ---
1304
+
1305
+ ##### `publicDnsName`<sup>Required</sup> <a name="publicDnsName" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.publicDnsName"></a>
1306
+
1307
+ ```typescript
1308
+ public readonly publicDnsName: string;
1309
+ ```
1310
+
1311
+ - *Type:* string
1312
+
1313
+ Public DNS of the instance (diagnostics only;
1314
+
1315
+ access is via SSM).
1316
+
1317
+ ---
1318
+
1319
+ ##### `role`<sup>Required</sup> <a name="role" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.role"></a>
1320
+
1321
+ ```typescript
1322
+ public readonly role: Role;
1323
+ ```
1324
+
1325
+ - *Type:* aws-cdk-lib.aws_iam.Role
1326
+
1327
+ The instance's IAM role (carries the permissions boundary).
1328
+
1329
+ ---
1330
+
1331
+ ##### `securityGroup`<sup>Required</sup> <a name="securityGroup" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.securityGroup"></a>
1332
+
1333
+ ```typescript
1334
+ public readonly securityGroup: SecurityGroup;
1335
+ ```
1336
+
1337
+ - *Type:* aws-cdk-lib.aws_ec2.SecurityGroup
1338
+
1339
+ The SSM-only security group (no inbound unless allowSshCidr is set).
1340
+
1341
+ ---
1342
+
1343
+ ##### `stackTag`<sup>Required</sup> <a name="stackTag" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.stackTag"></a>
1344
+
1345
+ ```typescript
1346
+ public readonly stackTag: string;
1347
+ ```
1348
+
1349
+ - *Type:* string
1350
+
1351
+ The discovery tag value written as `kirocrew:instance`.
1352
+
1353
+ ---
1354
+
1355
+
1356
+ ## Structs <a name="Structs" id="Structs"></a>
1357
+
1358
+ ### CrewBackupBucketProps <a name="CrewBackupBucketProps" id="@raindancers/raindancers-crew.CrewBackupBucketProps"></a>
1359
+
1360
+ Properties for {@link CrewBackupBucket}.
1361
+
1362
+ #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.CrewBackupBucketProps.Initializer"></a>
1363
+
1364
+ ```typescript
1365
+ import { CrewBackupBucketProps } from '@raindancers/raindancers-crew'
1366
+
1367
+ const crewBackupBucketProps: CrewBackupBucketProps = { ... }
1368
+ ```
1369
+
1370
+ #### Properties <a name="Properties" id="Properties"></a>
1371
+
1372
+ | **Name** | **Type** | **Description** |
1373
+ | --- | --- | --- |
1374
+ | <code><a href="#@raindancers/raindancers-crew.CrewBackupBucketProps.property.bucketName">bucketName</a></code> | <code>string</code> | Explicit bucket name. |
1375
+ | <code><a href="#@raindancers/raindancers-crew.CrewBackupBucketProps.property.noncurrentVersionExpirationDays">noncurrentVersionExpirationDays</a></code> | <code>number</code> | Days after which a NONCURRENT snapshot version is expired. |
1376
+ | <code><a href="#@raindancers/raindancers-crew.CrewBackupBucketProps.property.removalPolicy">removalPolicy</a></code> | <code>aws-cdk-lib.RemovalPolicy</code> | What happens to the bucket when the stack is destroyed. |
1377
+
1378
+ ---
1379
+
1380
+ ##### `bucketName`<sup>Optional</sup> <a name="bucketName" id="@raindancers/raindancers-crew.CrewBackupBucketProps.property.bucketName"></a>
1381
+
1382
+ ```typescript
1383
+ public readonly bucketName: string;
1384
+ ```
1385
+
1386
+ - *Type:* string
1387
+ - *Default:* CloudFormation-generated
1388
+
1389
+ Explicit bucket name.
1390
+
1391
+ Omit to let CloudFormation generate one.
1392
+
1393
+ ---
1394
+
1395
+ ##### `noncurrentVersionExpirationDays`<sup>Optional</sup> <a name="noncurrentVersionExpirationDays" id="@raindancers/raindancers-crew.CrewBackupBucketProps.property.noncurrentVersionExpirationDays"></a>
1396
+
1397
+ ```typescript
1398
+ public readonly noncurrentVersionExpirationDays: number;
1399
+ ```
1400
+
1401
+ - *Type:* number
1402
+ - *Default:* 90
1403
+
1404
+ Days after which a NONCURRENT snapshot version is expired.
1405
+
1406
+ Current
1407
+ versions are always kept. Set 0 to keep all versions forever.
1408
+
1409
+ ---
1410
+
1411
+ ##### `removalPolicy`<sup>Optional</sup> <a name="removalPolicy" id="@raindancers/raindancers-crew.CrewBackupBucketProps.property.removalPolicy"></a>
1412
+
1413
+ ```typescript
1414
+ public readonly removalPolicy: RemovalPolicy;
1415
+ ```
1416
+
1417
+ - *Type:* aws-cdk-lib.RemovalPolicy
1418
+ - *Default:* RemovalPolicy.RETAIN
1419
+
1420
+ What happens to the bucket when the stack is destroyed.
1421
+
1422
+ Defaults to
1423
+ RETAIN — the whole point is that the crew's learnings outlive the
1424
+ instance, so the backup must outlive a stack teardown too.
1425
+
1426
+ ---
1427
+
1428
+ ### CrewDataVolume <a name="CrewDataVolume" id="@raindancers/raindancers-crew.CrewDataVolume"></a>
1429
+
1430
+ How a per-crew durable EBS volume is exposed to the host and its container.
1431
+
1432
+ The device name the construct asks for (for example `/dev/sdf`) is NOT the
1433
+ kernel device name on Nitro/Graviton, where every EBS volume surfaces as an
1434
+ unpredictable `/dev/nvmeXn1`. The bootstrap therefore resolves each volume by
1435
+ a stable filesystem LABEL, never by the device path.
1436
+
1437
+ #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.CrewDataVolume.Initializer"></a>
1438
+
1439
+ ```typescript
1440
+ import { CrewDataVolume } from '@raindancers/raindancers-crew'
1441
+
1442
+ const crewDataVolume: CrewDataVolume = { ... }
1443
+ ```
1444
+
1445
+ #### Properties <a name="Properties" id="Properties"></a>
1446
+
1447
+ | **Name** | **Type** | **Description** |
1448
+ | --- | --- | --- |
1449
+ | <code><a href="#@raindancers/raindancers-crew.CrewDataVolume.property.crew">crew</a></code> | <code>string</code> | The crew this volume belongs to. |
1450
+ | <code><a href="#@raindancers/raindancers-crew.CrewDataVolume.property.deviceName">deviceName</a></code> | <code>string</code> | The block device name requested at attach time (a hint, not the kernel name). |
1451
+ | <code><a href="#@raindancers/raindancers-crew.CrewDataVolume.property.label">label</a></code> | <code>string</code> | The stable filesystem label the bootstrap resolves and mounts by. |
1452
+ | <code><a href="#@raindancers/raindancers-crew.CrewDataVolume.property.mountPath">mountPath</a></code> | <code>string</code> | The host mount path the container bind-mounts for `~/.kiro/crew`. |
1453
+
1454
+ ---
1455
+
1456
+ ##### `crew`<sup>Required</sup> <a name="crew" id="@raindancers/raindancers-crew.CrewDataVolume.property.crew"></a>
1457
+
1458
+ ```typescript
1459
+ public readonly crew: string;
1460
+ ```
1461
+
1462
+ - *Type:* string
1463
+
1464
+ The crew this volume belongs to.
1465
+
1466
+ ---
1467
+
1468
+ ##### `deviceName`<sup>Required</sup> <a name="deviceName" id="@raindancers/raindancers-crew.CrewDataVolume.property.deviceName"></a>
1469
+
1470
+ ```typescript
1471
+ public readonly deviceName: string;
1472
+ ```
1473
+
1474
+ - *Type:* string
1475
+
1476
+ The block device name requested at attach time (a hint, not the kernel name).
1477
+
1478
+ ---
1479
+
1480
+ ##### `label`<sup>Required</sup> <a name="label" id="@raindancers/raindancers-crew.CrewDataVolume.property.label"></a>
1481
+
1482
+ ```typescript
1483
+ public readonly label: string;
1484
+ ```
1485
+
1486
+ - *Type:* string
1487
+
1488
+ The stable filesystem label the bootstrap resolves and mounts by.
1489
+
1490
+ ---
1491
+
1492
+ ##### `mountPath`<sup>Required</sup> <a name="mountPath" id="@raindancers/raindancers-crew.CrewDataVolume.property.mountPath"></a>
1493
+
1494
+ ```typescript
1495
+ public readonly mountPath: string;
1496
+ ```
1497
+
1498
+ - *Type:* string
1499
+
1500
+ The host mount path the container bind-mounts for `~/.kiro/crew`.
1501
+
1502
+ ---
1503
+
1504
+ ### CrewRuntime <a name="CrewRuntime" id="@raindancers/raindancers-crew.CrewRuntime"></a>
1505
+
1506
+ Always-on runtime settings for the hosted crew, threaded into the crew `config.json` at boot. All fields are optional and default to the current gateway behaviour; omitting {@link RemoteCrewInstanceProps.crewRuntime} entirely reproduces today's `kirocrew setup --agent-only` + `kirocrew gateway` exactly.
1507
+
1508
+ Verified against KiroCrew v0.6.0: autopilot maps to `agent.approval_mode`,
1509
+ idle-close maps to `session.timeout_secs`, and the conductor roster ships
1510
+ with `setup --agent-only` (custom members are source-delivered JSON under
1511
+ `~/.kiro/agents/`).
1512
+
1513
+ #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.CrewRuntime.Initializer"></a>
1514
+
1515
+ ```typescript
1516
+ import { CrewRuntime } from '@raindancers/raindancers-crew'
1517
+
1518
+ const crewRuntime: CrewRuntime = { ... }
1519
+ ```
1520
+
1521
+ #### Properties <a name="Properties" id="Properties"></a>
1522
+
1523
+ | **Name** | **Type** | **Description** |
1524
+ | --- | --- | --- |
1525
+ | <code><a href="#@raindancers/raindancers-crew.CrewRuntime.property.autopilot">autopilot</a></code> | <code>boolean</code> | Enable Autopilot: the hosted crew auto-approves tool calls that pass its security checks (deny rules and sensitive-path blocks still apply). |
1526
+ | <code><a href="#@raindancers/raindancers-crew.CrewRuntime.property.disableIdleClose">disableIdleClose</a></code> | <code>boolean</code> | Keep the 24/7 brain session alive between events by disabling the idle session sweep. |
1527
+
1528
+ ---
1529
+
1530
+ ##### `autopilot`<sup>Optional</sup> <a name="autopilot" id="@raindancers/raindancers-crew.CrewRuntime.property.autopilot"></a>
1531
+
1532
+ ```typescript
1533
+ public readonly autopilot: boolean;
1534
+ ```
1535
+
1536
+ - *Type:* boolean
1537
+ - *Default:* false (interactive; gateway default)
1538
+
1539
+ Enable Autopilot: the hosted crew auto-approves tool calls that pass its security checks (deny rules and sensitive-path blocks still apply).
1540
+
1541
+ Sets
1542
+ `agent.approval_mode` to `"auto"` in config.json.
1543
+
1544
+ ---
1545
+
1546
+ ##### `disableIdleClose`<sup>Optional</sup> <a name="disableIdleClose" id="@raindancers/raindancers-crew.CrewRuntime.property.disableIdleClose"></a>
1547
+
1548
+ ```typescript
1549
+ public readonly disableIdleClose: boolean;
1550
+ ```
1551
+
1552
+ - *Type:* boolean
1553
+ - *Default:* false (default 3600s idle timeout applies)
1554
+
1555
+ Keep the 24/7 brain session alive between events by disabling the idle session sweep.
1556
+
1557
+ Sets `session.timeout_secs` to `0` (documented: "0 disables
1558
+ the idle sweep").
1559
+
1560
+ ---
1561
+
1562
+ ### CrewSource <a name="CrewSource" id="@raindancers/raindancers-crew.CrewSource"></a>
1563
+
1564
+ How the KiroCrew source is delivered to the instance at first boot.
1565
+
1566
+ Exactly one mode is active. When {@link sourceBucket} is set the instance
1567
+ downloads a source tarball from S3 (and is granted read on just that one
1568
+ object); otherwise it shallow-clones {@link kirocrewRef} from
1569
+ {@link kirocrewRepo}.
1570
+
1571
+ #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.CrewSource.Initializer"></a>
1572
+
1573
+ ```typescript
1574
+ import { CrewSource } from '@raindancers/raindancers-crew'
1575
+
1576
+ const crewSource: CrewSource = { ... }
1577
+ ```
1578
+
1579
+ #### Properties <a name="Properties" id="Properties"></a>
1580
+
1581
+ | **Name** | **Type** | **Description** |
1582
+ | --- | --- | --- |
1583
+ | <code><a href="#@raindancers/raindancers-crew.CrewSource.property.kirocrewRef">kirocrewRef</a></code> | <code>string</code> | Git ref (branch or tag) to install when cloning. |
1584
+ | <code><a href="#@raindancers/raindancers-crew.CrewSource.property.kirocrewRepo">kirocrewRepo</a></code> | <code>string</code> | Git repository to clone when no S3 source is configured. |
1585
+ | <code><a href="#@raindancers/raindancers-crew.CrewSource.property.sourceBucket">sourceBucket</a></code> | <code>string</code> | S3 bucket holding the source tarball (`kirocrew-src.tar.gz`). When set, the instance role is granted `s3:GetObject` on this object ONLY. Leave unset to clone from git instead. |
1586
+ | <code><a href="#@raindancers/raindancers-crew.CrewSource.property.sourceKey">sourceKey</a></code> | <code>string</code> | S3 key of the source tarball within {@link sourceBucket}. |
1587
+
1588
+ ---
1589
+
1590
+ ##### `kirocrewRef`<sup>Optional</sup> <a name="kirocrewRef" id="@raindancers/raindancers-crew.CrewSource.property.kirocrewRef"></a>
1591
+
1592
+ ```typescript
1593
+ public readonly kirocrewRef: string;
1594
+ ```
1595
+
1596
+ - *Type:* string
1597
+ - *Default:* 'main'
1598
+
1599
+ Git ref (branch or tag) to install when cloning.
1600
+
1601
+ Pin this to a released tag for reproducible, version-controlled deploys —
1602
+ the upstream launcher defaults to `main`, which drifts. This construct
1603
+ defaults to `main` only to match upstream; SET IT to a tag in production.
1604
+
1605
+ ---
1606
+
1607
+ ##### `kirocrewRepo`<sup>Optional</sup> <a name="kirocrewRepo" id="@raindancers/raindancers-crew.CrewSource.property.kirocrewRepo"></a>
1608
+
1609
+ ```typescript
1610
+ public readonly kirocrewRepo: string;
1611
+ ```
1612
+
1613
+ - *Type:* string
1614
+ - *Default:* 'https://github.com/kirodotdev/KiroCrew.git'
1615
+
1616
+ Git repository to clone when no S3 source is configured.
1617
+
1618
+ ---
1619
+
1620
+ ##### `sourceBucket`<sup>Optional</sup> <a name="sourceBucket" id="@raindancers/raindancers-crew.CrewSource.property.sourceBucket"></a>
1621
+
1622
+ ```typescript
1623
+ public readonly sourceBucket: string;
1624
+ ```
1625
+
1626
+ - *Type:* string
1627
+ - *Default:* clone from git (see kirocrewRepo / kirocrewRef)
1628
+
1629
+ S3 bucket holding the source tarball (`kirocrew-src.tar.gz`). When set, the instance role is granted `s3:GetObject` on this object ONLY. Leave unset to clone from git instead.
1630
+
1631
+ ---
1632
+
1633
+ ##### `sourceKey`<sup>Optional</sup> <a name="sourceKey" id="@raindancers/raindancers-crew.CrewSource.property.sourceKey"></a>
1634
+
1635
+ ```typescript
1636
+ public readonly sourceKey: string;
1637
+ ```
1638
+
1639
+ - *Type:* string
1640
+ - *Default:* none
1641
+
1642
+ S3 key of the source tarball within {@link sourceBucket}.
1643
+
1644
+ Required when
1645
+ `sourceBucket` is set; ignored otherwise.
1646
+
1647
+ ---
1648
+
1649
+ ### CrewWebhookIngressProps <a name="CrewWebhookIngressProps" id="@raindancers/raindancers-crew.CrewWebhookIngressProps"></a>
1650
+
1651
+ Properties for {@link CrewWebhookIngress}.
1652
+
1653
+ #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.Initializer"></a>
1654
+
1655
+ ```typescript
1656
+ import { CrewWebhookIngressProps } from '@raindancers/raindancers-crew'
1657
+
1658
+ const crewWebhookIngressProps: CrewWebhookIngressProps = { ... }
1659
+ ```
1660
+
1661
+ #### Properties <a name="Properties" id="Properties"></a>
1662
+
1663
+ | **Name** | **Type** | **Description** |
1664
+ | --- | --- | --- |
1665
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.code">code</a></code> | <code>aws-cdk-lib.aws_lambda.Code</code> | The code the ingress Lambda runs. |
1666
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.host">host</a></code> | <code><a href="#@raindancers/raindancers-crew.EcsCrewHost">EcsCrewHost</a></code> | The crew host whose tasks receive webhooks. |
1667
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.permissionsBoundaryArn">permissionsBoundaryArn</a></code> | <code>string</code> | ARN of an IAM permissions boundary applied to the Lambda's execution role. |
1668
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.vpc">vpc</a></code> | <code>aws-cdk-lib.aws_ec2.IVpc</code> | VPC to place the ingress Lambda in. |
1669
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.architecture">architecture</a></code> | <code>aws-cdk-lib.aws_lambda.Architecture</code> | Lambda architecture. |
1670
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.crewPort">crewPort</a></code> | <code>number</code> | TCP port on the crew task the Lambda reaches (the gateway/webhook port). |
1671
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.handler">handler</a></code> | <code>string</code> | The Lambda handler entry point. |
1672
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.runtime">runtime</a></code> | <code>aws-cdk-lib.aws_lambda.Runtime</code> | The Lambda runtime. |
1673
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.timeout">timeout</a></code> | <code>aws-cdk-lib.Duration</code> | Lambda timeout. |
1674
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.topic">topic</a></code> | <code>aws-cdk-lib.aws_sns.ITopic</code> | An existing SNS topic to subscribe the Lambda to. |
1675
+ | <code><a href="#@raindancers/raindancers-crew.CrewWebhookIngressProps.property.vpcSubnets">vpcSubnets</a></code> | <code>aws-cdk-lib.aws_ec2.SubnetSelection</code> | Subnets to place the ingress Lambda's ENIs in. |
1676
+
1677
+ ---
1678
+
1679
+ ##### `code`<sup>Required</sup> <a name="code" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.code"></a>
1680
+
1681
+ ```typescript
1682
+ public readonly code: Code;
1683
+ ```
1684
+
1685
+ - *Type:* aws-cdk-lib.aws_lambda.Code
1686
+
1687
+ The code the ingress Lambda runs.
1688
+
1689
+ The consumer supplies it: this construct
1690
+ wires the plumbing (SNS -> in-VPC Lambda -> task private IP) but does not
1691
+ ship an opinion about how a webhook payload maps to a crew.
1692
+
1693
+ ---
1694
+
1695
+ ##### `host`<sup>Required</sup> <a name="host" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.host"></a>
1696
+
1697
+ ```typescript
1698
+ public readonly host: EcsCrewHost;
1699
+ ```
1700
+
1701
+ - *Type:* <a href="#@raindancers/raindancers-crew.EcsCrewHost">EcsCrewHost</a>
1702
+
1703
+ The crew host whose tasks receive webhooks.
1704
+
1705
+ The task security group is
1706
+ granted a scoped inbound rule from this ingress Lambda's SG on the crew
1707
+ port only — the one controlled inbound exception to the egress-only model.
1708
+
1709
+ ---
1710
+
1711
+ ##### `permissionsBoundaryArn`<sup>Required</sup> <a name="permissionsBoundaryArn" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.permissionsBoundaryArn"></a>
1712
+
1713
+ ```typescript
1714
+ public readonly permissionsBoundaryArn: string;
1715
+ ```
1716
+
1717
+ - *Type:* string
1718
+
1719
+ ARN of an IAM permissions boundary applied to the Lambda's execution role.
1720
+
1721
+ The ingress Lambda runs consumer-triggered code, so it carries a boundary
1722
+ matching the rest of the construct.
1723
+
1724
+ ---
1725
+
1726
+ ##### `vpc`<sup>Required</sup> <a name="vpc" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.vpc"></a>
1727
+
1728
+ ```typescript
1729
+ public readonly vpc: IVpc;
1730
+ ```
1731
+
1732
+ - *Type:* aws-cdk-lib.aws_ec2.IVpc
1733
+
1734
+ VPC to place the ingress Lambda in.
1735
+
1736
+ Must be the same VPC as the crew tasks
1737
+ so the Lambda can reach a task's private ENI IP directly with NO VPC
1738
+ endpoint.
1739
+
1740
+ ---
1741
+
1742
+ ##### `architecture`<sup>Optional</sup> <a name="architecture" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.architecture"></a>
1743
+
1744
+ ```typescript
1745
+ public readonly architecture: Architecture;
1746
+ ```
1747
+
1748
+ - *Type:* aws-cdk-lib.aws_lambda.Architecture
1749
+ - *Default:* lambda.Architecture.ARM_64
1750
+
1751
+ Lambda architecture.
1752
+
1753
+ Defaults to arm64 to match the Graviton host.
1754
+
1755
+ ---
1756
+
1757
+ ##### `crewPort`<sup>Optional</sup> <a name="crewPort" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.crewPort"></a>
1758
+
1759
+ ```typescript
1760
+ public readonly crewPort: number;
1761
+ ```
1762
+
1763
+ - *Type:* number
1764
+ - *Default:* 5476
1765
+
1766
+ TCP port on the crew task the Lambda reaches (the gateway/webhook port).
1767
+
1768
+ ---
1769
+
1770
+ ##### `handler`<sup>Optional</sup> <a name="handler" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.handler"></a>
738
1771
 
739
1772
  ```typescript
740
- import { RemoteCrewInstance } from '@raindancers/raindancers-crew'
741
-
742
- RemoteCrewInstance.isConstruct(x: any)
1773
+ public readonly handler: string;
743
1774
  ```
744
1775
 
745
- Checks if `x` is a construct.
1776
+ - *Type:* string
1777
+ - *Default:* 'index.handler'
746
1778
 
747
- Use this method instead of `instanceof` to properly detect `Construct`
748
- instances, even when the construct library is symlinked.
1779
+ The Lambda handler entry point.
749
1780
 
750
- Explanation: in JavaScript, multiple copies of the `constructs` library on
751
- disk are seen as independent, completely different libraries. As a
752
- consequence, the class `Construct` in each copy of the `constructs` library
753
- is seen as a different class, and an instance of one class will not test as
754
- `instanceof` the other class. `npm install` will not create installations
755
- like this, but users may manually symlink construct libraries together or
756
- use a monorepo tool: in those cases, multiple copies of the `constructs`
757
- library can be accidentally installed, and `instanceof` will behave
758
- unpredictably. It is safest to avoid using `instanceof`, and using
759
- this type-testing method instead.
1781
+ ---
760
1782
 
761
- ###### `x`<sup>Required</sup> <a name="x" id="@raindancers/raindancers-crew.RemoteCrewInstance.isConstruct.parameter.x"></a>
1783
+ ##### `runtime`<sup>Optional</sup> <a name="runtime" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.runtime"></a>
762
1784
 
763
- - *Type:* any
1785
+ ```typescript
1786
+ public readonly runtime: Runtime;
1787
+ ```
764
1788
 
765
- Any object.
1789
+ - *Type:* aws-cdk-lib.aws_lambda.Runtime
1790
+ - *Default:* lambda.Runtime.NODEJS_20_X
1791
+
1792
+ The Lambda runtime.
1793
+
1794
+ Must be an arm64-compatible runtime to match the
1795
+ arm64 default host.
766
1796
 
767
1797
  ---
768
1798
 
769
- #### Properties <a name="Properties" id="Properties"></a>
1799
+ ##### `timeout`<sup>Optional</sup> <a name="timeout" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.timeout"></a>
770
1800
 
771
- | **Name** | **Type** | **Description** |
772
- | --- | --- | --- |
773
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
774
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.instance">instance</a></code> | <code>aws-cdk-lib.aws_ec2.Instance</code> | The EC2 instance (SSM target). |
775
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.instanceId">instanceId</a></code> | <code>string</code> | Instance id — the SSM target. |
776
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.publicDnsName">publicDnsName</a></code> | <code>string</code> | Public DNS of the instance (diagnostics only; |
777
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.role">role</a></code> | <code>aws-cdk-lib.aws_iam.Role</code> | The instance's IAM role (carries the permissions boundary). |
778
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.securityGroup">securityGroup</a></code> | <code>aws-cdk-lib.aws_ec2.SecurityGroup</code> | The SSM-only security group (no inbound unless allowSshCidr is set). |
779
- | <code><a href="#@raindancers/raindancers-crew.RemoteCrewInstance.property.stackTag">stackTag</a></code> | <code>string</code> | The discovery tag value written as `kirocrew:instance`. |
1801
+ ```typescript
1802
+ public readonly timeout: Duration;
1803
+ ```
1804
+
1805
+ - *Type:* aws-cdk-lib.Duration
1806
+ - *Default:* Duration.seconds(30)
1807
+
1808
+ Lambda timeout.
780
1809
 
781
1810
  ---
782
1811
 
783
- ##### `node`<sup>Required</sup> <a name="node" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.node"></a>
1812
+ ##### `topic`<sup>Optional</sup> <a name="topic" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.topic"></a>
784
1813
 
785
1814
  ```typescript
786
- public readonly node: Node;
1815
+ public readonly topic: ITopic;
787
1816
  ```
788
1817
 
789
- - *Type:* constructs.Node
1818
+ - *Type:* aws-cdk-lib.aws_sns.ITopic
1819
+ - *Default:* a new topic is created
790
1820
 
791
- The tree node.
1821
+ An existing SNS topic to subscribe the Lambda to.
1822
+
1823
+ Omit to create one.
792
1824
 
793
1825
  ---
794
1826
 
795
- ##### `instance`<sup>Required</sup> <a name="instance" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.instance"></a>
1827
+ ##### `vpcSubnets`<sup>Optional</sup> <a name="vpcSubnets" id="@raindancers/raindancers-crew.CrewWebhookIngressProps.property.vpcSubnets"></a>
796
1828
 
797
1829
  ```typescript
798
- public readonly instance: Instance;
1830
+ public readonly vpcSubnets: SubnetSelection;
799
1831
  ```
800
1832
 
801
- - *Type:* aws-cdk-lib.aws_ec2.Instance
1833
+ - *Type:* aws-cdk-lib.aws_ec2.SubnetSelection
1834
+ - *Default:* the VPC's private-with-egress subnets
802
1835
 
803
- The EC2 instance (SSM target).
1836
+ Subnets to place the ingress Lambda's ENIs in.
1837
+
1838
+ Should be the same private
1839
+ subnet the crew tasks run in so the Lambda reaches task IPs directly.
804
1840
 
805
1841
  ---
806
1842
 
807
- ##### `instanceId`<sup>Required</sup> <a name="instanceId" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.instanceId"></a>
1843
+ ### EcsCrewHostProps <a name="EcsCrewHostProps" id="@raindancers/raindancers-crew.EcsCrewHostProps"></a>
1844
+
1845
+ Properties for {@link EcsCrewHost}.
1846
+
1847
+ #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.EcsCrewHostProps.Initializer"></a>
808
1848
 
809
1849
  ```typescript
810
- public readonly instanceId: string;
1850
+ import { EcsCrewHostProps } from '@raindancers/raindancers-crew'
1851
+
1852
+ const ecsCrewHostProps: EcsCrewHostProps = { ... }
1853
+ ```
1854
+
1855
+ #### Properties <a name="Properties" id="Properties"></a>
1856
+
1857
+ | **Name** | **Type** | **Description** |
1858
+ | --- | --- | --- |
1859
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.permissionsBoundaryArn">permissionsBoundaryArn</a></code> | <code>string</code> | ARN of an IAM permissions boundary applied to the host instance role. |
1860
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.vpc">vpc</a></code> | <code>aws-cdk-lib.aws_ec2.IVpc</code> | VPC to run in. Passed in, never created here. |
1861
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.architecture">architecture</a></code> | <code><a href="#@raindancers/raindancers-crew.CrewArchitecture">CrewArchitecture</a></code> | CPU architecture of the host and the crew container images. |
1862
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.backupBucket">backupBucket</a></code> | <code><a href="#@raindancers/raindancers-crew.ICrewBackupBucket">ICrewBackupBucket</a></code> | An S3 backup bucket. |
1863
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crewCount">crewCount</a></code> | <code>number</code> | Number of Kiro Crew instances to host, each one ECS task/service. |
1864
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crewCpuShares">crewCpuShares</a></code> | <code>number</code> | Optional SOFT CPU shares per crew container (1024 = one vCPU). |
1865
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crewDataVolumeSizeGb">crewDataVolumeSizeGb</a></code> | <code>number</code> | Per-crew durable EBS data volume size in GiB. |
1866
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crewDataVolumeType">crewDataVolumeType</a></code> | <code>aws-cdk-lib.aws_ec2.EbsDeviceVolumeType</code> | Per-crew EBS volume type. |
1867
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crewImage">crewImage</a></code> | <code>string</code> | Container image reference for the crew task. |
1868
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crewMemoryHardLimitMiB">crewMemoryHardLimitMiB</a></code> | <code>number</code> | HARD memory cap (MiB) per crew container. |
1869
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crewMemoryReservationMiB">crewMemoryReservationMiB</a></code> | <code>number</code> | SOFT memory reservation (MiB) per crew container. |
1870
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crewPermissionsBoundaryArn">crewPermissionsBoundaryArn</a></code> | <code>string</code> | ARN of the pre-created shared crew permissions boundary (`arn:aws:iam::<account>:policy/kirocrew-crew-boundary`), applied to every per-crew task and execution role. |
1871
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.crews">crews</a></code> | <code>string[]</code> | Explicit crew names. |
1872
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.ecrRepositoryArn">ecrRepositoryArn</a></code> | <code>string</code> | ARN of the private ECR repository holding the crew image. |
1873
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.hostSubnets">hostSubnets</a></code> | <code>aws-cdk-lib.aws_ec2.SubnetSelection</code> | Subnet selection for the host ENI. |
1874
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.instanceType">instanceType</a></code> | <code>aws-cdk-lib.aws_ec2.InstanceType</code> | EC2 instance type for the single ECS-registered host. |
1875
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.logRetentionDays">logRetentionDays</a></code> | <code>number</code> | Days a crew's task logs are kept. |
1876
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.rootVolumeSizeGb">rootVolumeSizeGb</a></code> | <code>number</code> | gp3 root volume size in GiB for the host. |
1877
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.stackTag">stackTag</a></code> | <code>string</code> | Discovery tag value written as `kirocrew:ecs-host`. |
1878
+ | <code><a href="#@raindancers/raindancers-crew.EcsCrewHostProps.property.taskSubnets">taskSubnets</a></code> | <code>aws-cdk-lib.aws_ec2.SubnetSelection</code> | Subnet selection for the crew task ENIs. |
1879
+
1880
+ ---
1881
+
1882
+ ##### `permissionsBoundaryArn`<sup>Required</sup> <a name="permissionsBoundaryArn" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.permissionsBoundaryArn"></a>
1883
+
1884
+ ```typescript
1885
+ public readonly permissionsBoundaryArn: string;
811
1886
  ```
812
1887
 
813
1888
  - *Type:* string
814
1889
 
815
- Instance id — the SSM target.
1890
+ ARN of an IAM permissions boundary applied to the host instance role.
1891
+
1892
+ The host runs a prompt-injectable agent per crew, so its role MUST carry a
1893
+ boundary that caps blast radius. Required, not optional, matching
1894
+ {@link RemoteCrewInstanceProps.permissionsBoundaryArn }. Any valid managed-
1895
+ policy ARN is accepted here (this is the EC2/host boundary).
1896
+
1897
+ The per-crew task/execution roles take {@link crewPermissionsBoundaryArn},
1898
+ which is validated separately against the `kirocrew-crew-boundary` pattern
1899
+ the crew roles require.
816
1900
 
817
1901
  ---
818
1902
 
819
- ##### `publicDnsName`<sup>Required</sup> <a name="publicDnsName" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.publicDnsName"></a>
1903
+ ##### `vpc`<sup>Required</sup> <a name="vpc" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.vpc"></a>
820
1904
 
821
1905
  ```typescript
822
- public readonly publicDnsName: string;
1906
+ public readonly vpc: IVpc;
823
1907
  ```
824
1908
 
825
- - *Type:* string
1909
+ - *Type:* aws-cdk-lib.aws_ec2.IVpc
826
1910
 
827
- Public DNS of the instance (diagnostics only;
1911
+ VPC to run in. Passed in, never created here.
828
1912
 
829
- access is via SSM).
1913
+ The construct consumes a two-subnet host-NAT topology it does not build:
1914
+ one PUBLIC subnet (host ENI + Elastic IP + IGW route) and one PRIVATE
1915
+ subnet (task ENIs, `0.0.0.0/0` -> the host ENI, no IGW route). Select them
1916
+ with {@link hostSubnets} and {@link taskSubnets}.
830
1917
 
831
1918
  ---
832
1919
 
833
- ##### `role`<sup>Required</sup> <a name="role" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.role"></a>
1920
+ ##### `architecture`<sup>Optional</sup> <a name="architecture" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.architecture"></a>
834
1921
 
835
1922
  ```typescript
836
- public readonly role: Role;
1923
+ public readonly architecture: CrewArchitecture;
837
1924
  ```
838
1925
 
839
- - *Type:* aws-cdk-lib.aws_iam.Role
1926
+ - *Type:* <a href="#@raindancers/raindancers-crew.CrewArchitecture">CrewArchitecture</a>
1927
+ - *Default:* CrewArchitecture.ARM64
840
1928
 
841
- The instance's IAM role (carries the permissions boundary).
1929
+ CPU architecture of the host and the crew container images.
1930
+
1931
+ Must match
1932
+ {@link instanceType} when that is set.
842
1933
 
843
1934
  ---
844
1935
 
845
- ##### `securityGroup`<sup>Required</sup> <a name="securityGroup" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.securityGroup"></a>
1936
+ ##### `backupBucket`<sup>Optional</sup> <a name="backupBucket" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.backupBucket"></a>
846
1937
 
847
1938
  ```typescript
848
- public readonly securityGroup: SecurityGroup;
1939
+ public readonly backupBucket: ICrewBackupBucket;
849
1940
  ```
850
1941
 
851
- - *Type:* aws-cdk-lib.aws_ec2.SecurityGroup
1942
+ - *Type:* <a href="#@raindancers/raindancers-crew.ICrewBackupBucket">ICrewBackupBucket</a>
1943
+ - *Default:* no off-box backup
852
1944
 
853
- The SSM-only security group (no inbound unless allowSshCidr is set).
1945
+ An S3 backup bucket.
1946
+
1947
+ When set, each per-crew TASK role is granted write so
1948
+ the running container pushes its own snapshots off-box.
854
1949
 
855
1950
  ---
856
1951
 
857
- ##### `stackTag`<sup>Required</sup> <a name="stackTag" id="@raindancers/raindancers-crew.RemoteCrewInstance.property.stackTag"></a>
1952
+ ##### `crewCount`<sup>Optional</sup> <a name="crewCount" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crewCount"></a>
858
1953
 
859
1954
  ```typescript
860
- public readonly stackTag: string;
1955
+ public readonly crewCount: number;
861
1956
  ```
862
1957
 
863
- - *Type:* string
1958
+ - *Type:* number
1959
+ - *Default:* 1
864
1960
 
865
- The discovery tag value written as `kirocrew:instance`.
1961
+ Number of Kiro Crew instances to host, each one ECS task/service.
1962
+
1963
+ DEFAULT 1 — identical to today's single-crew behaviour, so existing
1964
+ consumers gain nothing new. The 55minutes consumer passes 3. Validated
1965
+ 1..8: awsvpc gives each task its own ENI, and (crewCount + 1) ENIs (the
1966
+ host ENI plus one per task) must fit the instance type's ENI budget.
866
1967
 
867
1968
  ---
868
1969
 
1970
+ ##### `crewCpuShares`<sup>Optional</sup> <a name="crewCpuShares" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crewCpuShares"></a>
869
1971
 
870
- ## Structs <a name="Structs" id="Structs"></a>
1972
+ ```typescript
1973
+ public readonly crewCpuShares: number;
1974
+ ```
871
1975
 
872
- ### CrewBackupBucketProps <a name="CrewBackupBucketProps" id="@raindancers/raindancers-crew.CrewBackupBucketProps"></a>
1976
+ - *Type:* number
1977
+ - *Default:* unset (shared CPU)
873
1978
 
874
- Properties for {@link CrewBackupBucket}.
1979
+ Optional SOFT CPU shares per crew container (1024 = one vCPU).
875
1980
 
876
- #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.CrewBackupBucketProps.Initializer"></a>
1981
+ Omit to
1982
+ leave CPU unconstrained (crews share the host CPU fairly under contention).
1983
+
1984
+ ---
1985
+
1986
+ ##### `crewDataVolumeSizeGb`<sup>Optional</sup> <a name="crewDataVolumeSizeGb" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crewDataVolumeSizeGb"></a>
877
1987
 
878
1988
  ```typescript
879
- import { CrewBackupBucketProps } from '@raindancers/raindancers-crew'
1989
+ public readonly crewDataVolumeSizeGb: number;
1990
+ ```
880
1991
 
881
- const crewBackupBucketProps: CrewBackupBucketProps = { ... }
1992
+ - *Type:* number
1993
+ - *Default:* 20
1994
+
1995
+ Per-crew durable EBS data volume size in GiB.
1996
+
1997
+ Always encrypted, always
1998
+ `deleteOnTermination: false` (a crew's `~/.kiro/crew` learnings must
1999
+ outlive an instance replacement, matching the CrewBackupBucket RETAIN
2000
+ intent).
2001
+
2002
+ ---
2003
+
2004
+ ##### `crewDataVolumeType`<sup>Optional</sup> <a name="crewDataVolumeType" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crewDataVolumeType"></a>
2005
+
2006
+ ```typescript
2007
+ public readonly crewDataVolumeType: EbsDeviceVolumeType;
882
2008
  ```
883
2009
 
884
- #### Properties <a name="Properties" id="Properties"></a>
2010
+ - *Type:* aws-cdk-lib.aws_ec2.EbsDeviceVolumeType
2011
+ - *Default:* ec2.EbsDeviceVolumeType.GP3
885
2012
 
886
- | **Name** | **Type** | **Description** |
887
- | --- | --- | --- |
888
- | <code><a href="#@raindancers/raindancers-crew.CrewBackupBucketProps.property.bucketName">bucketName</a></code> | <code>string</code> | Explicit bucket name. |
889
- | <code><a href="#@raindancers/raindancers-crew.CrewBackupBucketProps.property.noncurrentVersionExpirationDays">noncurrentVersionExpirationDays</a></code> | <code>number</code> | Days after which a NONCURRENT snapshot version is expired. |
890
- | <code><a href="#@raindancers/raindancers-crew.CrewBackupBucketProps.property.removalPolicy">removalPolicy</a></code> | <code>aws-cdk-lib.RemovalPolicy</code> | What happens to the bucket when the stack is destroyed. |
2013
+ Per-crew EBS volume type.
891
2014
 
892
2015
  ---
893
2016
 
894
- ##### `bucketName`<sup>Optional</sup> <a name="bucketName" id="@raindancers/raindancers-crew.CrewBackupBucketProps.property.bucketName"></a>
2017
+ ##### `crewImage`<sup>Optional</sup> <a name="crewImage" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crewImage"></a>
895
2018
 
896
2019
  ```typescript
897
- public readonly bucketName: string;
2020
+ public readonly crewImage: string;
898
2021
  ```
899
2022
 
900
2023
  - *Type:* string
901
- - *Default:* CloudFormation-generated
2024
+ - *Default:* 'public.ecr.aws/kirocrew/crew:latest'
902
2025
 
903
- Explicit bucket name.
2026
+ Container image reference for the crew task.
904
2027
 
905
- Omit to let CloudFormation generate one.
2028
+ When {@link ecrRepositoryArn}
2029
+ is set this is typically the repo URI with a tag; otherwise a public
2030
+ registry reference.
906
2031
 
907
2032
  ---
908
2033
 
909
- ##### `noncurrentVersionExpirationDays`<sup>Optional</sup> <a name="noncurrentVersionExpirationDays" id="@raindancers/raindancers-crew.CrewBackupBucketProps.property.noncurrentVersionExpirationDays"></a>
2034
+ ##### `crewMemoryHardLimitMiB`<sup>Optional</sup> <a name="crewMemoryHardLimitMiB" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crewMemoryHardLimitMiB"></a>
910
2035
 
911
2036
  ```typescript
912
- public readonly noncurrentVersionExpirationDays: number;
2037
+ public readonly crewMemoryHardLimitMiB: number;
913
2038
  ```
914
2039
 
915
2040
  - *Type:* number
916
- - *Default:* 90
2041
+ - *Default:* 2048
917
2042
 
918
- Days after which a NONCURRENT snapshot version is expired.
2043
+ HARD memory cap (MiB) per crew container.
919
2044
 
920
- Current
921
- versions are always kept. Set 0 to keep all versions forever.
2045
+ A crew is OOM-killed at this
2046
+ ceiling, so no single crew can consume the whole host. Set the SUM of hard
2047
+ caps at or below (physical RAM minus host + ECS-agent headroom) for a hard
2048
+ cross-crew guarantee — see the host-OOM caution in the README.
922
2049
 
923
2050
  ---
924
2051
 
925
- ##### `removalPolicy`<sup>Optional</sup> <a name="removalPolicy" id="@raindancers/raindancers-crew.CrewBackupBucketProps.property.removalPolicy"></a>
2052
+ ##### `crewMemoryReservationMiB`<sup>Optional</sup> <a name="crewMemoryReservationMiB" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crewMemoryReservationMiB"></a>
926
2053
 
927
2054
  ```typescript
928
- public readonly removalPolicy: RemovalPolicy;
2055
+ public readonly crewMemoryReservationMiB: number;
929
2056
  ```
930
2057
 
931
- - *Type:* aws-cdk-lib.RemovalPolicy
932
- - *Default:* RemovalPolicy.RETAIN
2058
+ - *Type:* number
2059
+ - *Default:* 1024
933
2060
 
934
- What happens to the bucket when the stack is destroyed.
2061
+ SOFT memory reservation (MiB) per crew container.
935
2062
 
936
- Defaults to
937
- RETAIN — the whole point is that the crew's learnings outlive the
938
- instance, so the backup must outlive a stack teardown too.
2063
+ ECS uses it for
2064
+ placement; a crew may burst above it when the host has spare RAM, so idle
2065
+ crews cost little.
939
2066
 
940
2067
  ---
941
2068
 
942
- ### CrewRuntime <a name="CrewRuntime" id="@raindancers/raindancers-crew.CrewRuntime"></a>
943
-
944
- Always-on runtime settings for the hosted crew, threaded into the crew `config.json` at boot. All fields are optional and default to the current gateway behaviour; omitting {@link RemoteCrewInstanceProps.crewRuntime} entirely reproduces today's `kirocrew setup --agent-only` + `kirocrew gateway` exactly.
945
-
946
- Verified against KiroCrew v0.6.0: autopilot maps to `agent.approval_mode`,
947
- idle-close maps to `session.timeout_secs`, and the conductor roster ships
948
- with `setup --agent-only` (custom members are source-delivered JSON under
949
- `~/.kiro/agents/`).
950
-
951
- #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.CrewRuntime.Initializer"></a>
2069
+ ##### `crewPermissionsBoundaryArn`<sup>Optional</sup> <a name="crewPermissionsBoundaryArn" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crewPermissionsBoundaryArn"></a>
952
2070
 
953
2071
  ```typescript
954
- import { CrewRuntime } from '@raindancers/raindancers-crew'
955
-
956
- const crewRuntime: CrewRuntime = { ... }
2072
+ public readonly crewPermissionsBoundaryArn: string;
957
2073
  ```
958
2074
 
959
- #### Properties <a name="Properties" id="Properties"></a>
2075
+ - *Type:* string
2076
+ - *Default:* no crew boundary (declared degraded mode; see FargateCrew)
960
2077
 
961
- | **Name** | **Type** | **Description** |
962
- | --- | --- | --- |
963
- | <code><a href="#@raindancers/raindancers-crew.CrewRuntime.property.autopilot">autopilot</a></code> | <code>boolean</code> | Enable Autopilot: the hosted crew auto-approves tool calls that pass its security checks (deny rules and sensitive-path blocks still apply). |
964
- | <code><a href="#@raindancers/raindancers-crew.CrewRuntime.property.disableIdleClose">disableIdleClose</a></code> | <code>boolean</code> | Keep the 24/7 brain session alive between events by disabling the idle session sweep. |
2078
+ ARN of the pre-created shared crew permissions boundary (`arn:aws:iam::<account>:policy/kirocrew-crew-boundary`), applied to every per-crew task and execution role.
2079
+
2080
+ Separate from {@link permissionsBoundaryArn} because the crew roles enforce
2081
+ the `kirocrew-crew-boundary` policy name (a different boundary from the
2082
+ host's), and validating them together would force one ARN to satisfy two
2083
+ distinct patterns. Optional, mirroring {@link FargateCrew}'s declared
2084
+ degraded mode: omit it only when no crew-boundary creator exists yet.
965
2085
 
966
2086
  ---
967
2087
 
968
- ##### `autopilot`<sup>Optional</sup> <a name="autopilot" id="@raindancers/raindancers-crew.CrewRuntime.property.autopilot"></a>
2088
+ ##### `crews`<sup>Optional</sup> <a name="crews" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.crews"></a>
969
2089
 
970
2090
  ```typescript
971
- public readonly autopilot: boolean;
2091
+ public readonly crews: string[];
972
2092
  ```
973
2093
 
974
- - *Type:* boolean
975
- - *Default:* false (interactive; gateway default)
2094
+ - *Type:* string[]
2095
+ - *Default:* crew-1 .. crew-<crewCount>
976
2096
 
977
- Enable Autopilot: the hosted crew auto-approves tool calls that pass its security checks (deny rules and sensitive-path blocks still apply).
2097
+ Explicit crew names.
978
2098
 
979
- Sets
980
- `agent.approval_mode` to `"auto"` in config.json.
2099
+ Each must match the {@link FargateCrew} regex
2100
+ `^[a-z0-9]([a-z0-9-]{0,30}[a-z0-9])?$`; the log group, roles, and secret
2101
+ namespace are derived from it. When omitted, names are generated as
2102
+ `crew-1`..`crew-<crewCount>`. When set, the list length must equal
2103
+ {@link crewCount}.
981
2104
 
982
2105
  ---
983
2106
 
984
- ##### `disableIdleClose`<sup>Optional</sup> <a name="disableIdleClose" id="@raindancers/raindancers-crew.CrewRuntime.property.disableIdleClose"></a>
2107
+ ##### `ecrRepositoryArn`<sup>Optional</sup> <a name="ecrRepositoryArn" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.ecrRepositoryArn"></a>
985
2108
 
986
2109
  ```typescript
987
- public readonly disableIdleClose: boolean;
2110
+ public readonly ecrRepositoryArn: string;
988
2111
  ```
989
2112
 
990
- - *Type:* boolean
991
- - *Default:* false (default 3600s idle timeout applies)
2113
+ - *Type:* string
2114
+ - *Default:* public registry; no pull grant
992
2115
 
993
- Keep the 24/7 brain session alive between events by disabling the idle session sweep.
2116
+ ARN of the private ECR repository holding the crew image.
994
2117
 
995
- Sets `session.timeout_secs` to `0` (documented: "0 disables
996
- the idle sweep").
2118
+ Leave unset when
2119
+ the image is pulled from a public registry. When set, each per-crew
2120
+ execution role gets a pull grant scoped to this one repository.
997
2121
 
998
2122
  ---
999
2123
 
1000
- ### CrewSource <a name="CrewSource" id="@raindancers/raindancers-crew.CrewSource"></a>
2124
+ ##### `hostSubnets`<sup>Optional</sup> <a name="hostSubnets" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.hostSubnets"></a>
1001
2125
 
1002
- How the KiroCrew source is delivered to the instance at first boot.
2126
+ ```typescript
2127
+ public readonly hostSubnets: SubnetSelection;
2128
+ ```
1003
2129
 
1004
- Exactly one mode is active. When {@link sourceBucket} is set the instance
1005
- downloads a source tarball from S3 (and is granted read on just that one
1006
- object); otherwise it shallow-clones {@link kirocrewRef} from
1007
- {@link kirocrewRepo}.
2130
+ - *Type:* aws-cdk-lib.aws_ec2.SubnetSelection
2131
+ - *Default:* one public subnet in the VPC
1008
2132
 
1009
- #### Initializer <a name="Initializer" id="@raindancers/raindancers-crew.CrewSource.Initializer"></a>
2133
+ Subnet selection for the host ENI.
1010
2134
 
1011
- ```typescript
1012
- import { CrewSource } from '@raindancers/raindancers-crew'
2135
+ This is the PUBLIC subnet (IGW-routed,
2136
+ carries the Elastic IP), because the host does the NAT for the tasks.
1013
2137
 
1014
- const crewSource: CrewSource = { ... }
2138
+ ---
2139
+
2140
+ ##### `instanceType`<sup>Optional</sup> <a name="instanceType" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.instanceType"></a>
2141
+
2142
+ ```typescript
2143
+ public readonly instanceType: InstanceType;
1015
2144
  ```
1016
2145
 
1017
- #### Properties <a name="Properties" id="Properties"></a>
2146
+ - *Type:* aws-cdk-lib.aws_ec2.InstanceType
2147
+ - *Default:* m7g.2xlarge (arm64) / m7i.2xlarge (x86_64), matching RemoteCrewInstance
1018
2148
 
1019
- | **Name** | **Type** | **Description** |
1020
- | --- | --- | --- |
1021
- | <code><a href="#@raindancers/raindancers-crew.CrewSource.property.kirocrewRef">kirocrewRef</a></code> | <code>string</code> | Git ref (branch or tag) to install when cloning. |
1022
- | <code><a href="#@raindancers/raindancers-crew.CrewSource.property.kirocrewRepo">kirocrewRepo</a></code> | <code>string</code> | Git repository to clone when no S3 source is configured. |
1023
- | <code><a href="#@raindancers/raindancers-crew.CrewSource.property.sourceBucket">sourceBucket</a></code> | <code>string</code> | S3 bucket holding the source tarball (`kirocrew-src.tar.gz`). When set, the instance role is granted `s3:GetObject` on this object ONLY. Leave unset to clone from git instead. |
1024
- | <code><a href="#@raindancers/raindancers-crew.CrewSource.property.sourceKey">sourceKey</a></code> | <code>string</code> | S3 key of the source tarball within {@link sourceBucket}. |
2149
+ EC2 instance type for the single ECS-registered host.
2150
+
2151
+ The type STAYS a settable prop: the 55minutes consumer passes
2152
+ `new ec2.InstanceType('m9g.xlarge')`. Never hardcoded to one family.
1025
2153
 
1026
2154
  ---
1027
2155
 
1028
- ##### `kirocrewRef`<sup>Optional</sup> <a name="kirocrewRef" id="@raindancers/raindancers-crew.CrewSource.property.kirocrewRef"></a>
2156
+ ##### `logRetentionDays`<sup>Optional</sup> <a name="logRetentionDays" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.logRetentionDays"></a>
1029
2157
 
1030
2158
  ```typescript
1031
- public readonly kirocrewRef: string;
2159
+ public readonly logRetentionDays: number;
1032
2160
  ```
1033
2161
 
1034
- - *Type:* string
1035
- - *Default:* 'main'
2162
+ - *Type:* number
2163
+ - *Default:* 30
1036
2164
 
1037
- Git ref (branch or tag) to install when cloning.
2165
+ Days a crew's task logs are kept.
1038
2166
 
1039
- Pin this to a released tag for reproducible, version-controlled deploys —
1040
- the upstream launcher defaults to `main`, which drifts. This construct
1041
- defaults to `main` only to match upstream; SET IT to a tag in production.
2167
+ One of the CloudWatch retention values
2168
+ (see {@link FargateCrew}).
1042
2169
 
1043
2170
  ---
1044
2171
 
1045
- ##### `kirocrewRepo`<sup>Optional</sup> <a name="kirocrewRepo" id="@raindancers/raindancers-crew.CrewSource.property.kirocrewRepo"></a>
2172
+ ##### `rootVolumeSizeGb`<sup>Optional</sup> <a name="rootVolumeSizeGb" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.rootVolumeSizeGb"></a>
1046
2173
 
1047
2174
  ```typescript
1048
- public readonly kirocrewRepo: string;
2175
+ public readonly rootVolumeSizeGb: number;
1049
2176
  ```
1050
2177
 
1051
- - *Type:* string
1052
- - *Default:* 'https://github.com/kirodotdev/KiroCrew.git'
2178
+ - *Type:* number
2179
+ - *Default:* 60
1053
2180
 
1054
- Git repository to clone when no S3 source is configured.
2181
+ gp3 root volume size in GiB for the host.
2182
+
2183
+ Always encrypted.
1055
2184
 
1056
2185
  ---
1057
2186
 
1058
- ##### `sourceBucket`<sup>Optional</sup> <a name="sourceBucket" id="@raindancers/raindancers-crew.CrewSource.property.sourceBucket"></a>
2187
+ ##### `stackTag`<sup>Optional</sup> <a name="stackTag" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.stackTag"></a>
1059
2188
 
1060
2189
  ```typescript
1061
- public readonly sourceBucket: string;
2190
+ public readonly stackTag: string;
1062
2191
  ```
1063
2192
 
1064
2193
  - *Type:* string
1065
- - *Default:* clone from git (see kirocrewRepo / kirocrewRef)
2194
+ - *Default:* 'kirocrew'
1066
2195
 
1067
- S3 bucket holding the source tarball (`kirocrew-src.tar.gz`). When set, the instance role is granted `s3:GetObject` on this object ONLY. Leave unset to clone from git instead.
2196
+ Discovery tag value written as `kirocrew:ecs-host`.
2197
+
2198
+ Must match
2199
+ `[a-zA-Z0-9-]{1,51}`. The cluster is named `kirocrew-crew-<stackTag>`.
1068
2200
 
1069
2201
  ---
1070
2202
 
1071
- ##### `sourceKey`<sup>Optional</sup> <a name="sourceKey" id="@raindancers/raindancers-crew.CrewSource.property.sourceKey"></a>
2203
+ ##### `taskSubnets`<sup>Optional</sup> <a name="taskSubnets" id="@raindancers/raindancers-crew.EcsCrewHostProps.property.taskSubnets"></a>
1072
2204
 
1073
2205
  ```typescript
1074
- public readonly sourceKey: string;
2206
+ public readonly taskSubnets: SubnetSelection;
1075
2207
  ```
1076
2208
 
1077
- - *Type:* string
1078
- - *Default:* none
2209
+ - *Type:* aws-cdk-lib.aws_ec2.SubnetSelection
2210
+ - *Default:* the VPC's private-with-egress subnets
1079
2211
 
1080
- S3 key of the source tarball within {@link sourceBucket}.
2212
+ Subnet selection for the crew task ENIs.
1081
2213
 
1082
- Required when
1083
- `sourceBucket` is set; ignored otherwise.
2214
+ This is the PRIVATE subnet whose
2215
+ `0.0.0.0/0` route points at the host ENI (no IGW route). Tasks get no
2216
+ public IP.
1084
2217
 
1085
2218
  ---
1086
2219